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
API
class
The 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
}
APIRequest
protocol
The 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.