Simple GET request without parsing:
let resource = APIResource(path: "simple-get")
let api = APIService().base("https://coreapi.free.beeceptor.com/")
api.load(resource) { (json, data) -> NSDictionary? in
return json as? NSDictionary
} completion: { (result) in
print(result)
}
Simple GET request to get user (comforms to Decodable)
let resource = APIResource(path: "user")
let api = APIService().base("https://coreapi.free.beeceptor.com/")
api.load(resource, User.self) { (result) in
print(result)
}
More complex example. Subclass the original APIService, set default params, add logging:
class MyAPIService: APIService {
override init() {
super.init()
initialize()
}
func initialize() {
self
.base("https://coreapi.free.beeceptor.com/")
.headers(values: ["api-key": "some-value"])
.onLog { (value) in
print(value)
}
}
func makePost(completion: @escaping (Result<NSDictionary,Error>)->Void) {
let resource = POST(path: "custom").body(["key":"value"])
self.load(resource) { (json, data) -> NSDictionary? in
return json as? NSDictionary
} completion: { (result) in
completion(result)
}
}
func anotherExample(completion: @escaping (Result<Status,Error>)->Void) {
let payload = User(id: 5, name: "Test")
let resource = POST(path: "custom").payload(payload)
self.load(resource, Status.self) { (result) in
completion(result)
}
}
}
then you can use it as:
let customAPI = MyAPIService()
///
self.customAPI.makePost { (result) in
print(result)
}
self.customAPI.anotherExample { (result) in
print(result)
}
The core idea:
- describe a resource
- call a service
both APIResource and APIService highly customisable, support chaining for parameters
let resource = APIResource()
resource
.path("users")
.post()
.header("value", for: "key")
.data(data)
// .body(["key1": "value", "key2": 42])
// .payload(EncodableModel())
.query(["limit": 100, "offset": 0])
let service = APIService()
service
.base(my_api_base_url)
.headers(["value": "key"])
.onLog({ value in
print(value)
})
.onError401({ url in
//i.e. refresh token
//then service.resume()
//or
//service.cancelAllRequests()
})
.onSignature({ (path) -> [String : String] in
return ["Authorization": "Bearer xxxxxxx"]
})
function load(...) returns an operation
all requests are executed acynchronously in a background thread
a completion block returns a result in a backgroung thread as well. it's your responsibility to handle the result in a main thread if necessary:
weak var welf = self
let resource = APIResource(path: "users")
let api = APIService().base("https://coreapi.free.beeceptor.com/")
api.load(resource, [Users].self) { (result) in
switch result {
case .success(let items):
DispatchQueue.main.async {
welf?.items = items
welf?.tableView.reloadData()
}
case .failure(let error):
print(error)
}
:-)