54
34

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ゆめみ その2Advent Calendar 2019

Day 5

もう絶対迷わないエラーレスポンスの作り方【RFC7807】

Last updated at Posted at 2019-12-04

この記事は「ゆめみ その2 Advent Calendar 2019」の5日目の記事です。

ある日のこと…

スクリーンショット 2019-12-03 23.08.30.png

「いきなりそんなこと言われても…」

上司「ついでにいろんなところで使いまわせるように普遍的なのにしてね」

「えぇ…」

「こういう時にエラーレスポンスが標準化されてRFCでまとめられてたらいいのになぁ…」

ありました

RFC7807 : Problem Details for HTTP APIs

RFC7807では開発においてHTTP APIのために新しくエラーレスポンスを定義するのを避けるために、プログラムが読み取れるような問題詳細(Problem Details)をapplication/problem+jsonまたはapplication/problem+xmlで定義しています。

問題詳細(Problem Details)ってなんぞや?

type, title, status, detail, instance + αからなるオブジェクトで、これを用いてどんな問題が発生しているのかを説明します。

type (String) :エラーの詳細ドキュメントへのURL
title (String) :人間が読むことのできる短いサマリー
status (String) :サーバによって生成されたHTTPステータスコード
detail (String) :人間が読むことのできる説明文
instance (String) :問題の発生箇所の参照URI

ちなみにこれを全て使う必要はなく、状況によって使い分けたり新しく必要なメンバーを追加することでもできます。

Example

ECサイトにおいてユーザのキャッシュ残高が足りないことを示すエラーの場合

HTTP/1.1 403 Forbidden
Content-Type: application/problem+json
Content-Language: en

{
 // エラー詳細ドキュメントへのURL
 "type": "https://example.com/probs/out-of-credit",
 // 短いサマリー 
 "title": "You do not have enough credit.",
 // 説明文 
 "detail": "Your current balance is 30, but that costs 50.",
 // 問題発生箇所のURI
 "instance": "/account/12345/msgs/abc",
 // statuは省略

 // 口座の残高
 "balance": 30,
 // 扱うことのできる口座へのリンク
 "accounts": [
    "/account/12345",
    "/account/67890"
 ]
}

この例だと新たにbalanceaccountsを定義することで、現在の口座の残高とそのユーザが扱うことのできる口座へのリンクを追加しています。

注意点

問題詳細(Problem Details)を定義する上でいくつか注意しなくてはいけないことがあります。

1.情報漏洩
2.発生場所へのリンク
3.statusメンバーについて

1.情報漏洩

親切心からあれもこれもと必要以上に情報を記載するとエラーレスポンスの情報から予期せぬシステムにアクセスされたり、最悪ユーザのプライバシーを侵害してしまう可能性があります。

上記のECサイトの例ではユーザの残高や使用できる口座のリンクを見れてしまいます。

通信が完全に暗号化されていたり安全が保証されているならいいですが、そうでない場合はできる限り避けましょう。

2.発生場所へのリンク

問題が発生した際にデバッグが簡単になるからとスタックダンプやエラーログをそのまま出力したり、実装の詳細を掲載することは避けましょう。

悪意あるユーザに見られた場合、サーバの実装の詳細やデータなどが公開される危険性があります。

3.statusメンバーについて

statusメンバーはあくまでHTTPステータスをコピーしているだけです。

一般的なソフトウェアがこのメンバーで伝達されるステータスコードを認識したり利用したりする可能性は低いので、あまり使われることはないでしょう。

ただし複数のサーバを中継したりする場合は中継したサーバでHTTPステータスが変わる場合がある(らしい)ので、そういう時に使用しましょう。

参考:実務で使えるようにいい感じにしてみる

ここまでを踏まえた上で実用で使えそうなエラーレスポンスを考えてみます。(あくまで個人の意見です)

HTTP/1.1 403 Forbidden
Content-Type: application/problem+json
Content-Language: en

{
 "title": "FORBIDDEN",
 "detail": "Please contact your administrator.",
 "error_code": "403-001
}

あとはきちんとIP制限された詳細ドキュメントが既にある or 作る予定ならばtypeを追加しても良いと思います。

…えっ、これだけかって?

だって下手に詳細を出力してインシデントの危険性を上げるよりも、エラーが出たらerror_codeだけ伝えて保守してる管理者にログ見てもらった方が早いし安全だと思うんです(個人の意見です)

それに実装する際にerror_codeで出力するエラーコードをきっちり設計して適切に使用すれば、それを見ただけでどこでどんな問題が発生しているかを判別できるのでエラーを特定するのも楽になる…んじゃないですかね(個人の意見です)

最後に

結局のところ、それぞれのプロダクトに合った最適なエラーレスポンスというのは要件や設計によって大幅に変わってくるので、これは参考程度に収めて頑張ってBestなエラーレスポンスを設計しましょう。

自分もまだまだ模索中なので、もっと良い方法を思いついたら是非ともコメントで教えてくださると助かります。

後日談

「やっとエラーレスポンスの設計終わったから、ちょっとだけ休憩時間できたな」

「今のうちにゆめみ その2 Advent Calendar 2019に投稿する記事でも書くか!」

上司「次はエラーコードの設計よろしく」

「えっ」

参考資料

Problem Details for HTTP APIs

54
34
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
54
34

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?