Installation • Usage • Issues • Contributing • License
A micro version of the Moya network abstraction layer written in Swift.
Installation is supported via CocoaPods, Carthage, SwiftPM and Mint.
Create an Api enum
with all supported endpoints as cases
with the request parameters/data specified as parameters.
For example, when writing a client for the Microsoft Translator API:
enum MicrosoftTranslatorApi {
case languages
case translate(texts: [String], from: Language, to: [Language])
}
Note that the Language
type used above does not necessarily need to be an Encodable
type:
enum Language: String {
case english = "en"
case german = "de"
case japanese = "jp"
case turkish = "tr"
}
Add an extension for your Api enum
that makes it JsonApi
compliant, which means you need to add implementations for the following protocol:
protocol JsonApi {
var decoder: JSONDecoder { get }
var encoder: JSONEncoder { get }
var baseUrl: URL { get }
var headers: [String: String] { get }
var path: String { get }
var method: Method { get }
var queryParameters: [(key: String, value: String)] { get }
var bodyData: Data? { get }
}
Use switch
statements over self
to differentiate between the cases (if needed) and to provide the appropriate data the protocol asks for (using Value Bindings).
Toggle me to see an example
extension MicrosoftTranslatorApi: JsonApi {
var decoder: JSONDecoder {
return JSONDecoder()
}
var encoder: JSONEncoder {
return JSONEncoder()
}
var baseUrl: URL {
return URL(string: "https://api.cognitive.microsofttranslator.com")!
}
var path: String {
switch self {
case .languages:
return "/languages"
case .translate:
return "/translate"
}
}
var method: Method {
switch self {
case .languages:
return .get
case .translate:
return .post
}
}
var queryParameters: [(key: String, value: String)] {
var urlParameters: [(String, String)] = [(key: "api-version", value: "3.0")]
switch self {
case .languages:
break
case let .translate(_, sourceLanguage, targetLanguages, _):
urlParameters.append((key: "from", value: sourceLanguage.rawValue))
for targetLanguage in targetLanguages {
urlParameters.append((key: "to", value: targetLanguage.rawValue))
}
}
return urlParameters
}
var bodyData: Data? {
switch self {
case .translate:
return nil // no request data needed
case let .translate(texts, _, _, _):
return try! encoder.encode(texts)
}
}
var headers: [String: String] {
switch self {
case .languages:
return [:]
case .translate:
return [
"Ocp-Apim-Subscription-Key": "<SECRET>",
"Content-Type": "application/json"
]
}
}
}
Call an API endpoint providing a Decodable
type of the expected result (if any) by using this method pre-implemented in the JsonApi
protocol:
func request<ResultType: Decodable>(type: ResultType.Type) -> Result<ResultType, JsonApiError>
For example:
let endpoint = MicrosoftTranslatorApi.translate(texts: ["Test"], from: .english, to: [.german, .japanese, .turkish])
switch endpoint.request(type: [String: String].self) {
case let .success(translationsByLanguage):
// use the already decoded `[String: String]` result
case let .failure(error):
// error handling
}
Note that you can also use the throwing get()
function of Swift 5's Result
type instead of using a switch
statement:
let endpoint = MicrosoftTranslatorApi.translate(texts: ["Test"], from: .english, to: [.german, .japanese, .turkish])
let translationsByLanguage = try endpoint.request(type: [String: String].self)
// use the already decoded `[String: String]` result
There's even useful functional methods defined on the Results
type like map()
, flatMap()
or mapError()
and flatMapError()
. See the "Transforming Result" section in this article for more information.
See the file CONTRIBUTING.md.
This library is released under the MIT License. See LICENSE for details.