All Projects → jaychang0917 → Simpleapiclient Ios

jaychang0917 / Simpleapiclient Ios

Licence: mit
A configurable api client based on Alamofire4 and RxSwift4 for iOS

Programming Languages

swift
15916 projects
swift4
162 projects

Projects that are alternatives of or similar to Simpleapiclient Ios

Rxswiftexamples
Examples and resources for RxSwift.
Stars: ✭ 930 (+1267.65%)
Mutual labels:  rxswift, alamofire
Rxalamofire
RxSwift wrapper around the elegant HTTP networking in Swift Alamofire
Stars: ✭ 1,503 (+2110.29%)
Mutual labels:  rxswift, alamofire
Rxmarvel
Playing around marvel public API with RxSwift, Argo, Alamofire
Stars: ✭ 86 (+26.47%)
Mutual labels:  rxswift, alamofire
Moya
Network abstraction layer written in Swift.
Stars: ✭ 13,607 (+19910.29%)
Mutual labels:  rxswift, alamofire
WhatFilm
Simple iOS app using TMDb API and RxSwift
Stars: ✭ 35 (-48.53%)
Mutual labels:  rxswift, alamofire
Moya-Gloss
Gloss bindings for Moya
Stars: ✭ 37 (-45.59%)
Mutual labels:  rxswift, alamofire
Moyasugar
🍯 Syntactic sugar for Moya
Stars: ✭ 165 (+142.65%)
Mutual labels:  rxswift, alamofire
Tswechat
A WeChat alternative. Written in Swift 5.
Stars: ✭ 3,674 (+5302.94%)
Mutual labels:  rxswift, alamofire
Evreflection
Reflection based (Dictionary, CKRecord, NSManagedObject, Realm, JSON and XML) object mapping with extensions for Alamofire and Moya with RxSwift or ReactiveSwift
Stars: ✭ 954 (+1302.94%)
Mutual labels:  rxswift, alamofire
Github
Ruby interface to GitHub API
Stars: ✭ 1,081 (+1489.71%)
Mutual labels:  api-client
Jetchat
 Swift5.0编写的简仿微信聊天应用,完美支持表情键盘、单聊、群聊、本地消息会话缓存。
Stars: ✭ 61 (-10.29%)
Mutual labels:  rxswift
Quandl Python
Stars: ✭ 1,076 (+1482.35%)
Mutual labels:  api-client
Api Php Client
PHP client of Akeneo PIM API
Stars: ✭ 56 (-17.65%)
Mutual labels:  api-client
Loginwithrxswift
A demo with Sign up and Login function With RxSwift
Stars: ✭ 63 (-7.35%)
Mutual labels:  rxswift
Rxswiftext
A collection of Rx operators & tools not found in the core RxSwift distribution
Stars: ✭ 1,080 (+1488.24%)
Mutual labels:  rxswift
Unboxedalamofire
[Deprecated] Alamofire + Unbox: the easiest way to download and decode JSON into swift objects.
Stars: ✭ 65 (-4.41%)
Mutual labels:  alamofire
Anaconda
A Go client library for the Twitter 1.1 API
Stars: ✭ 1,077 (+1483.82%)
Mutual labels:  api-client
Wikipedir
R's MediaWiki API client library
Stars: ✭ 54 (-20.59%)
Mutual labels:  api-client
Moneybird Php Client
PHP Client for Moneybird V2
Stars: ✭ 67 (-1.47%)
Mutual labels:  api-client
Igdb
Go client for the Internet Game Database API
Stars: ✭ 65 (-4.41%)
Mutual labels:  api-client

SimpleApiClient

Swift CI Status Version License Platform

A configurable api client based on Alamofire4 and RxSwift4 for iOS

Requirements

  • iOS 8.0+
  • Swift 4

Table of Contents

Installation

SimpleApiClient is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'SimpleApiClient'

Basic Usage

Step 1

Configurate the api client

let config = SimpleApiClient.Config(
  baseUrl: "https://api.github.com",
  defaultParameters: ["foo": "bar"],
  defaultHeaders: ["foo": "bar"],
  timeout: 120, // default is 60s
  certificatePins: [
    CertificatePin(hostname: "https://api.github.com", certificateUrl: Bundle.main.url(forResource: "serverCert", withExtension: "cer")!)
  ],
  errorMessageKeyPath: "message",
  jsonDecoder: JSONDecoder(),  // default is JSONDecoder()
  isMockResponseEnabled: true, // default is false
  logHandler: { request, response in
    ...
  },
  errorHandler: { error in
    // you can centralize the handling of general error here
    switch error {
    case .authenticationError(let code, let message):
      ...
    case .clientError(let code, let message):
      ...
    case .serverError(let code, let message):
      ...
    case .networkError(let source):
      ...
    case .sslError(let source):
      ...
    case .uncategorizedError(let source):
      ...
    }
  }
)

let githubClient = SimpleApiClient(config: config)

Step 2

Create the API

import SimpleApiClient

struct GetRepoApi: SimpleApi {
  let user: String
  let repo: String
  
  var path: String {
    return "/repos/\(user)/\(repo)"
  }
  
  var method: HTTPMethod {
    return .get
  }
  
  // optional
  var parameters: Parameters {
    return [:]
  }
  
  // optional
  var headers: HTTPHeaders {
    return [:]
  }
}

extension SimpleApiClient {
  func getRepo(user: String, repo: String) -> Observable<Repo> {
    return request(api: GetRepoApi(user: user, repo: repo))
  }
}

Step 3

Use observe() to enqueue the call, do your stuff in corresponding parameter block. All blocks run on main thread by default and are optional.

githubClient.getRepo(user: "foo", repo: "bar")
  .observe(
    onStart: { print("show loading") },
    onEnd: { print("hide loading") },
    onSuccess: { print("sucess: \($0)") },
    onError: { print("error: \($0)" }
  )

Model

The library uses JSONDecoder to deserialize JSON to model object, so the model should conform to Decodable or Codable

struct User: Decodable {
  let name: String
  let profileUrl: URL
  // if the serialized name is different from the property name
  private enum CodingKeys: String, CodingKey {
    case name = "login"
    case profileUrl = "avatar_url"
  }
}

Unwrap Response by KeyPath

Sometimes the api response includes metadata that we don't need, but in order to map the response we create a wrapper class and make the function return that wrapper class. This approach leaks the implementation of service to calling code.

Assuming the response json looks like the following:

{
  total_count: 33909,
  incomplete_results: false,
  foo: {
    bar: {
      items: [
        {
          login: "foo",
          ...
        }
        ...
      ]
    }
  }
}

And you only need the items part, implement Unwrappable to indicate which part of response you want.

struct GetUsersApi: SimpleApi, Unwrappable {
  ... 
  
  var responseKeyPath: String {
    return "foo.bar.items"
  }
}

// then your response will be a list of User
extension SimpleApiClient {
  func getUsers(query: String) -> Observable<[User]> {
    return request(api: GetUsersApi(query: query))
  }
}

Upload File(s)

To upload file(s), make the API implements Uploadable to provide Multiparts

struct UploadImageApi: SimpleApi, Uploadable {
  ...
  
  var multiParts: [MultiPart] {
    let multiPart = MultiPart(data: UIImageJPEGRepresentation(image, 1)!, name: "imagefile", filename: "image.jpg", mimeType: "image/jpeg")
    return [multiPart]
  }
}

extension SimpleApiClient {
  func uploadImage(image: UIImage) -> Observable<Image> {
    return request(api: UploadImageApi(image))
  }
}

Serial / Parallel Calls

Serial

githubClient.foo()
  .then { foo in githubClient.bar(foo.name) }
  .observe(...)

Serial then Parallel

githubClient.foo()
  .then { foo in githubClient.bar(foo.name) }
  .thenAll { bar in 
    (githubClient.baz(bar.name), githubClient.qux(bar.name)) // return a tuple
  }
  .observe(...)

Parallel

SimpleApiClient.all(
  githubApi.foo(),
  githubApi.bar()
)
.observe(...)

Parallel then Serial

SimpleApiClient.all(
  githubApi.foo(),
  githubApi.bar()
).then { array -> // the return type is Array<Any>, you should cast them, e.g. let foo = array[0] as! Foo
  githubApi.baz()
}.observe(...)

Retry Interval / Exponential backoff

githubClient.getUsers("foo")
  .retry(delay: 5, maxRetryCount: 3) // retry up to 3 times, each time delays 5 seconds
  .retry(exponentialDelay: 5, maxRetryCount: 3) // retry up to 3 times, each time delays 5^n seconds, where n = {1,2,3}
  .observe(...)

Call Cancellation

Auto Call Cancellation

The call will be cancelled when the object is deallocated.

githubClient.getUsers("foo")
  .cancel(when: self.rx.deallocated)
  .observe(...)

Cancel call manually

let call = githubClient.getUsers("foo").observe(...)

call.cancel()

Mock Response

To enable response mocking, set SimpleApiClient.Config.isMockResponseEnabled to true and make the API implements Mockable to provide MockResponse.

Mock sample json data

To make the api return a successful response with provided json

struct GetUsersApi: SimpleApi, Mockable {
  ...
  
  var mockResponse: MockResponse {
    let file = Bundle.main.url(forResource: "get_users", withExtension: "json")!
    return MockResponse(jsonFile: file)
  }
}

Mock status

To make the api return a client side error with provided json

struct GetUsersApi: SimpleApi, Mockable {
  ...
  
  var mockResponse: MockResponse {
    let file = Bundle.main.url(forResource: "get_users_error", withExtension: "json")!
    return MockResponse(jsonFile: file, status: .clientError)
  }
}

the parameter jsonFile of MockResponse is optional, you can set the status only, then you receive empty string.

Possible Status values:

public enum Status {
  case success
  case authenticationError
  case clientError
  case serverError
  case networkError
  case sslError
}

To mock a response with success status only, you should return Observable<Nothing>.

struct DeleteRepoApi: SimpleApi, Mockable {
  ...
  
  var mockResponse: MockResponse {
    return MockResponse(status: .success)
  }
}

extension SimpleApiClient {
  func deleteRepo(id: String) -> Observable<Nothing> {
    return request(api: DeleteRepoApi(id: id))
  }
}

Author

jaychang0917, [email protected]

License

SimpleApiClient is available under the MIT license. See the LICENSE file for more info.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].