前提
APIKitとCodableとの連携という素晴らしい記事を参考に、Codableとの連携を終えていること
したいこと
ほとんどのWebAPIでは、エラー時のレスポンスが定義されています。
こんな感じに。
{
"status": 400,
"message": "hogehoge"
}
それをこの中で補足したい! ということ
Session.send(request) { result in
switch result {
case .success(let response):
print(response)
case .failure(let err):
print(err)
}
}
参考
APIKit作者様のブログ「APIKit: レスポンスに応じた独自のエラーを投げる」
↑はCodable非対応なので、これをCodable対応にしましょう。
いざ、実装!
Requestオブジェクトに追加
現在はおそらくこんな感じだと思います。
APIKit_extension.swift
extension APIKit.Request where Response: Decodable {
var dataParser: DataParser {
return JSONDataParser() as DataParser
}
func response(from object: Any, urlResponse: HTTPURLResponse) throws -> Response {
let decoder = JSONDecoder()
return try decoder.decode(Response.self, from: object as! Data)
}
}
ここにメソッドとエラーを定義します。(エラーは単純化したサンプル)
APIKit_extension.swift
extension APIKit.Request where Response: Decodable {
var dataParser: DataParser {
return JSONDataParser() as DataParser
}
func response(from object: Any, urlResponse: HTTPURLResponse) throws -> Response {
let decoder = JSONDecoder()
return try decoder.decode(Response.self, from: object as! Data)
}
func intercept(object: Any, urlResponse: HTTPURLResponse) throws -> Any {
// 200番台でない場合は、MyErrorを投げる
guard (200..<300).contains(urlResponse.statusCode) else {
// ひとまず、Decodableな構造体に値を埋める
let decoder = JSONDecoder()
let obj_decoded = try decoder.decode(TmpMyError.self, from: object as! Data)
// それもとにMyErrorを生成して投げる
throw MyError(object: obj_decoded)
}
return object
}
}
struct TmpMyError: Decodable {
let status: Int
let message: String
}
struct MyError: Error {
let status: Int
let message: String
init(object: TmpMyError) {
status = object.status
message = object.message
}
}
呼び出し側にcaseを追加
Session.send(request) { result in
switch result {
case .success(let response):
print(response)
case .failure(.responseError(let err as MyError)):
print("MyServiceError Message", err.message)
case .failure(let err):
print("Unknown error", err)
}
}
#おわりに
これが最適解かは分かりませんが、快適なAPIクライアントを開発できました。