/api-common

A small library to interface with different APIs using a common core

Primary LanguageSwiftMIT LicenseMIT

APICommon

A small wrapper around URLSession that allows quick and generic building of api responses and tasks

How to use

There are two core parts to this wrapper

  • The API class itself
  • The APIRequest protocol

The API class

At its core, the class is very simple. Initialize the class by providing the base URL and a date decoding strategy (either custom or built-in). Then, make a request by building a struct that conforms to the APIRequest protocol, passing an instance to request<T: APIRequest>(_) and either using the callback or binding it to an RxSwift observable.

However, if you need to add headers, customize params, etc. then override the build(_ : APIRequest) method by subclassing the API class. If you want headers and params auto-added, call super.build(request) inside, or just rewrite the whole thing if you need a custom request method

A simple request works as follows.

// Assuming we have a struct already that conforms to APIRequest called "CurrentWeatherRequest"

let request = CurrentWeatherRequest(zipcode: "44444")
api.request(request) { response, error in
    // Check for errors and handle the response, which is already deserialized
}

The APIRequest protocol

This is the core structure for making requests and decoding data.

It contains an associated type that must conform to Decodable. This is the type that will be returned by either the completion or the Single if you are using RxSwift.

It also contains several properties associated with a request. These must all be set, though some of them (i.e. method) can be set to a default value.

In order to use this protocol, create a struct that conforms to this protocol. Any params or headers that must be set can also be created in this struct. A simple example is as follows (using the CurrentWeatherRequest example from before)

struct CurrentWeatherRequest: APIRequest {
    // Assuming we have a struct that conforms to Decodable called "CurrentWeatherResponse"
    // Since we are conforming to Decodable, this could also be wrapped in a Dictionary or Array if necessary
    typealias Response = CurrentWeatherResponse
    
    var accessMethod: AccessMethod { .apiKey } // The type of authentication required 
    var endpoint    : String { "/current" } // The actual endpoint, without including the base url
    var method      : HTTPRequestMethod { .GET } // The HTTP request type
    var headers     : Dictionary<String, String> { [:] } // Any headers required (not including the api key)
    var params      : Dictionary<String, String> { return ["zipcode": zipcode] } // Any params required for the request
    
    var expectedResponseCode: Int? { 200 }
    
    let zipcode: String
}

If you are writing this inside of a library, do not expose this struct. Instead, extend the API class as follows

public extension API {
    func getCurrentWeather(_ zip: String, completion: @escaping (Result<T.Response, Error>) -> Void) {
        return self.request(CurrentWeatherRequest(zipcode: zip))
    }
    
    // or with RxSwift
    
    func getCurrentWeather(_ zip: String) -> Single<CurrentWeatherResponse> {
        return self.request(CurrentWeatherRequest(zipcode: zip))
    }
}

Then, in your app, simply call api.getCurrentWeather("44444") to access it.

Installation

SPM

Include the following line in your dependencies

.package(url: "https://github.com/MatrixSenpai/api-common.git", .exact("1.0.0"))

And import it as follows

.target(name: "MyTarget", dependencies: ["APICommon"])
// OR
.target(name: "MyTarget", dependencies: ["APICommon", "RxAPICommon"])

CocoaPods

Simply include the pod name, as follows

# This line includes the Rx extensions by default
pod 'APICommon'

# If you DON'T want the extensions, use this line
pod 'APICommon/Core'

Carthage

Carthage is not, nor will it ever be supported by my work. Should someone desire to open a PR and include it, do so and I will update the documentation.

Other Notes

This work is licenced under the MIT license. See the LICENSE.md file for further information.