BambooHero

iOSアプリ開発と株式投資をメインに色々書きます

APIKitのエラーハンドリングを整理する

f:id:bamboohero:20210620031807p:plain

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の公式ドキュメントに記載がありますが、ホストの名前解決に失敗した場合や、ネットワークの問題でサーバに接続できないときなどにこのエラーがスローされるようです。

https://developer.apple.com/documentation/foundation/urlsessiontaskdelegate/1411610-urlsession


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型の関連値を持っているので、どんなエラーでもスローすることが可能です。独自のエラーをスローする場合は、エラーハンドリングの分岐も増えることになります。