Web APIで発生するエラーの対処
エラーが発生しないシステムは存在しない。回復できるエラーからは回復し、回復できないエラーからは適切な情報を残して終了することがシステムには求められる。
Web APIも同様だ。サーバ内でエラーが発生することもある。ネットワーク障害の影響を受けることもある。そもそもネットワークは動的で不安定なものなので、なおさら考慮が必要なポイントでもある。
今回はWeb APIでエラーが発生した際の対処についてクライアントの視点で述べる。
エラーの種類
Web APIで発生するエラーは大きく2つに分類することができる。
- ネットワークエラー
- APIエラー
以降、この2つに分けて対処法を見ていく。
共通
最初にネットワークエラーとAPIエラーに共通するポイントを取り上げる。
Timeout
- 送信処理や再送処理にTimeoutを実装すること。
- Timeoutがないとアプリケーションがフリーズしてしまう
Fallback
- 結果が取得できなかったときに既定値やデフォルト値を使用することをFallbackと呼ぶ
- 最新の結果を得ることが必須でないデータについてはFallbackを実装することで堅牢性が向上する
ネットワークエラー
事象
- Requestがサーバに到達しない
- Responseがクライアントに到達していない
原因
Destination host unreachable
- サーバへのルートがない
Destination port unreachable
- サーバに到達したがポートが開いていない
Protocol error (using HTTP when HTTPS required)
- サーバのポートに到達したがなんらかのエラーが発生した
Connection timeout
- 上記以外のなんらかの理由でサーバに到達できない
- 一番多い
対処法
- 過渡的な障害の可能性があるのでRetryが基本
- 一定回数Retryしたら情報を残してFallbackするか終了すること
- Retry間隔はExponential Backoffすること
- Retry時にはAPIのIdempotencyに留意すること
Exponential Backoff
- 失敗するごとに次のRetryまでの間隔を長くすること
- 失敗が続くほど次のRetryが成功する可能性は低くなる
- 成功する可能性が低いRetryの試行頻度を下げることでリソースの無駄な消費を防ぐことが目的
Idempotency(冪等性)
- Idempotencyとは同じ処理を何度も実行したとき、最初だけResourceのStateを変更し、以降は何度実行してもStateが変わらないこと
- PUT/GET/DELETEはIdempotent
- 何回、Retryで再送しても安全
- POSTはIdempotentではない
- 万が一、重複してサーバに到達すると不整合が発生してしまう
- 慎重に再送する必要がある
APIエラー
事象
- サーバに到達したがそこで問題が発生した
- クライアントはサーバが送るResponse Codeで問題の発生とその内容を知ることができる
Response Code
- 1xx Informational
- 2xx Success
- 3xx Redirection
- 4xx Client error
- 5xx Server error
対処法
- エラーを2種類に分ける
- 回復可能なもの
- Retryする
- 回復不可能、もしくは継続するのにユーザの介入が必要なもの
- 解析に焦点を合わせる
- 回復可能なもの
1. 回復不可能なエラーの場合
対処方針
- ResponseのStatus Codeを見る
- HTTP Headerを見る
- Bodyを見る
- 回復不可能と判断した場合は情報を残して終了する
- 正当な要求でない可能性があるためFallbackはしない
例
- 400 Bad Request
- 401 Unauthorized
- 403 Forbidden
2. 回復可能なエラーの場合
対処方針
- ResponseのStatus Codeを見る
- HTTP Headerを見る
- Bodyを見る
- 確認した内容を反映してRetryする
- それでもだめな場合は情報を残してFallbackするか終了する
対処例
405 Method Not Allowed
- ResponseのAllowヘッダを確認して適切なMethodでRetryする
408 Request Timeout
- Exponential BackoffでRetryする
- 低速デバイスが巨大なデータをPOSTするときなどに発生する
411 Length Required
- Content-Length ヘッダーを追加してRetryする
- Content-Lengthはメッセージボディの長さを表す
429 Too Many Requests
- DOS攻撃対策や契約上の上限値超過などによって返ってくることがある
- Responseに待ち時間を示すRetry-Afterヘッダが含まれている場合は指定された時間待った後にRetryする