APIKitではどのようなエラーが定義されていて、それらがどういうときにスローされるかを整理します。
APIKitでAPIClientを実装するときに、エラーハンドリング周りをどう実装するかを考える際の参考になるかと思います。
前提とサンプルコード
APIKitが提供しているデフォルトの実装、つまりURLSessionAdapterを使用することを前提としています。
本記事執筆時点では、APIKitでは以下3つのエラーを定義しています。
- RequestError
- ResponseError
- SessionTaskError
HTTP通信処理の起点となるsend(_:callbackQueue:handler:)
メソッドを実行してエラーになると、handler
にはSessionTaskErrorが渡されます。なのでRequestErrorとResponseErrorはSessionTaskErrorに内包される形になります。
エラーのパターンを整理すると、こんな感じのコードになります。
Session.shared.send(request) { result in
switch result {
case .success(let response):
// 成功時の処理
case .failure(let sessionTaskError):
switch sessionTaskError {
case .connectionError(let error):
break
case .requestError(let error as RequestError):
switch error {
case .invalidBaseURL(let url):
break
case .unexpectedURLRequest(let urlRequest):
break
}
case .requestError(let error):
break
case .responseError(let error as ResponseError):
switch error {
case .nonHTTPURLResponse(let urlResponse):
break
case .unacceptableStatusCode(let statusCode):
break
case .unexpectedObject(let object):
break
}
case .responseError(let error):
break
}
}
}
以降では、各エラーがどのようなときにスローされるかを説明していきます。
SessionTaskError.connectionError
クライアント側の問題によってHTTPリクエストに失敗した場合、このエラーがスローされます。
このエラーはURLSessionTaskDelegate.urlSession(_:task:didCompleteWithError:)
が受け取ったものです。
URLSessionTaskDelegateの公式ドキュメントに記載がありますが、ホストの名前解決に失敗した場合や、ネットワークの問題でサーバに接続できないときなどにこのエラーがスローされるようです。
RequestError.invalidBaseURL
RequestのbaseURL
プロパティの値が不正な場合にスローされます。
RequestError.unexpectedURLRequest
APIKitのデフォルト実装ではスローされません。
例えば、Requestプロトコルのintercept(urlRequest:)
メソッドを独自に実装する際に、渡されたURLRequestが不正な状態だったときにスローするように実装すると良いかもしれません。
ResponseError.nonHTTPURLResponse
APIKitのデフォルト実装ではスローされません。
SessionクラスはHTTPURLResponseを期待しているにもかかわらず、独自のSessionAdapterが別のURLResponse実装クラスを返すような実装にしているとスローされてしまいます。
ResponseError.unacceptableStatusCode
HTTPステータスコードが2xx
以外だった場合にスローされます。
Requestプロトコルのintercept(object:urlResponse:)
メソッドのデフォルト実装でそのように実装されています。
ResponseError.unexpectedObject
APIKitのデフォルト実装ではスローされません。
例えば、Requestプロトコルのresponse(from:urlRequest:)
メソッドを独自に実装する際に、デコード処理に失敗したときなどにスローするように実装すると良いかもしれません。
まとめ
APIKitのデフォルト実装を前提に、各種エラーがどのようなときにスローされるかを説明しました。
一部のエラーは定義のみされていて、スローするかどうかは実装者に任されています。
なお、SessionTaskErrorの各エラーケースはError型の関連値を持っているので、どんなエラーでもスローすることが可能です。独自のエラーをスローする場合は、エラーハンドリングの分岐も増えることになります。