CocoaPods trunk is moving to be read-only. Read more on the blog, there are 18 months to go.

WebAPIKit 0.1.1

WebAPIKit 0.1.1

TestsTested
LangLanguage SwiftSwift
License MIT
ReleasedLast Release Apr 2017
SwiftSwift Version 3.0
SPMSupports SPM

Maintained by Evan Liu.



 
Depends on:
Alamofire~> 4.4
Result~> 3.2
 

WebAPIKit 0.1.1

  • By
  • Evan Liu

WebAPIKit is a network abstraction layer to build web API clients.

Features

Easy to setup

final class GitHubAPI: WebAPIProvider {
    let baseURL = URL(string: "https://api.github.com")!
    func getUser(login: String, handler: @escaping ResultHandler) {
        makeRequest(path: "/users/\(login)").send(handler: handler)
    }
}
GitHubAPI().getUser(login: "WebAPIKit") {
    if case .success(let response) = $0, response.status.isSuccess {
        // Read from response.data and/or response.headers
    }
}

Strong typed response

(Using Marshal for json parsing here but you can use any library as your choice)

struct User: ResponseJSONData {
    var login: String
    var name: String?
    init(json: [String: Any]) throws {
        login = try json.value(for: "login")
        name = try json.value(for: "name")
    }
}
extension GitHubAPI {
    func getUser(login: String, handler: @escaping (Result<User, WebAPIError>) -> Void) {
        makeRequest(path: "/users/\(login)").sendAndDecode(handler: handler)
    }
}
GitHubAPI().getUser(login: "WebAPIKit") {
    if case .success(let user) = $0 {
        // user is of type User
    }
}

Plugins

final class GitHubAPI: WebAPIProvider {
    let baseURL = URL(string: "https://api.github.com")!
    let plugins = PluginHub()
        .addRequestProcessor(RequestHeaderSetter(key: .accept, value: "application/vnd.github.v3+json"))
        .addResponseProcessor(ResponseStatusValidator())
}

Requests can also have their own plugins:

extension GitHubAPI {
    func getUser(login: String, handler: @escaping ResultHandler) {
        makeRequest(path: "/users/\(login)").addPlugin(MyRequestHook()).send(handler: handler)
    }
}

Authentication

final class MyServerAPI: WebAPIProvider {
    let baseURL = URL(string: "https://my-server.com/api/v1")!
    let requireAuthentication = true
    var authentication: WebAPIAuthentication = NoneAuthentication()
}
class MyLoginController {
    func login(user: String, password: String) {
        myServer.authentication = BasicAuthentication(user: user, password: password)
    }
}

Requests will not be sent if requireAuthentication is true but there is no valid authentication. Except some endpoints may not require authentication.

extension MyServerAPI {
    func sayHi(message: String, handler: @escaping ResultHandler) {
        makeRequest(path: "/hi", method: .post)
            .addParameter(key: "message", value: message)
            .setRequireAuthentication(false)
            .send(handler: handler)
    }
}

Stub

final class GitHubAPI: StubbableProvider {
    let baseURL = URL(string: "https://api.github.com")!
    var httpClient: HTTPClient? // Use Alamofire.SessionManager.default if not defined
}
// Stub for development
class SomeBusyClass {
    fucn someMethod() {
        let client = gitHub.stubClient()
        client.stub(path: "/users", method: .post).withStatus(.code201)
        client.stub(template: "/users/{login}").withTemplatedJSON { ["login": $0["login"]!, "name": "User"] }
        client.stub().withStatus(.code404) // All other requests will fail with 404
    }
}
// Stub for testing
class SomeTestCase {
    func testSomeMethod() {
        // ... After stub setup
        client.stub(path: "/users").withJSON([["login": "test", "name": "Tester"]])
        client.stub(path: "/users", method: .post).withStatus(.code201).withMode(.manual)

        // ... After some method calls
        XCTAssertTrue(client.hasConnection)
        
        client.lastConnection!.respond() // For POST /users. GET /users will respond with json data automatically
        // ... Verify success behaviour 

        XCTAssertFalse(client.hasActiveConnection) // No connection that is not yet responded to or canceled
    }
}

Cancel requests

extension GitHubAPI {
    func getUser(login: String, handler: @escaping ResultHandler) -> Cancelable {
        return makeRequest(path: "/users/\(login)").send(handler: handler)
    }
}
class SomeClass {
    func someMethod() {
        let connection = gitHub.getUser(login: "WebAPIKit") { ... }
        
        // No longer needed now
        connection.cancel()
    }
}

TODO

WebAPIKit is still working in progress.

Before Release:

  • [ ] OAuth support
  • [ ] Reactive Extensions (RxSwift & ReactiveSwift)
  • [ ] Higher test coverage (currently 62.5%)
  • [ ] Documentation
  • [ ] Demo app GitHubExplorer

Furture versions (or extension libraries):

  • [ ] Request queues
  • [ ] REST resources