How to Think About HTTP Status Codes

2年ほど前の記事になりますが、HTTP ステータスコードについて解説している記事を、勉強を兼ねて翻訳してみました。ところどころ自信がないので間違いなどあればご指摘いただけますと幸いです。

原文はこちら。
mnot’s blog: How to Think About HTTP Status Codes


HTTP ステータスコードには少なからず混乱や戸惑いを感じることがある。私は長年に亘ってストレスを抱えた開発者から次のような相談を受けている。

409400 のどちらを使うべきでしょうか?または 500 がいいでしょうか?私の同僚はどんなときにでも 200 を使おうとしているし、向かいの席のひとは新しいステータスコードを定義しようとしています。

HTTP ステータスコードのことやその使い方について掘り下げてみましょう。

Two Levels of Meaning

HTTP ステータスコードは構造化されている。1桁目はレスポンスの種類を示し、他2桁はそのレスポンスを具体的にどのように処理するかを示す。定義済みのレスポンスの種類は次の通り。

例えば、201 Created2xxステータスコードで、成功したレスポンスを示す。01 は、リクエストによって Location ヘッダーに指定されたURLにあるリソースが作成されたことを示す。

同様に、409 Conflict4xxステータスコードで、サーバーの処理によるものではなく、リクエストに問題があることを意味する。4xx09 は、リクエストがサーバーの状態と競合していることをクライアントに伝えており、再度リクエストを送信する前に競合を解決する必要がある。

1桁目の数字はそれ自身が意味を持っているため、ステータスコードの受け取り側はそれを調べてレスポンスの意味を理解できるが、どのように処理するべきかは明確ではない。これにより、新しく定義されたステータスコードを一般的に処理できるように適切に格下げすることができる(きちんと設計されていれば)。(※)
(※訳注: 適切に汎化できるという意図だと思われる)

Generic Semantics

ステータスコードは、すべての HTTP リソースに適用される可能性があると定義されていることを理解することも重要である。私たちは 汎用的なセマンティクス (※) と呼んでいる(まさに HTTP メソッドと同様に)。
(※訳注: この訳が相応しいかどうかちょっと自信がない...)

これを知ることは混乱の原因を明らかにする。アプリケーション固有のセマンティクスを汎用的なセマンティクスにマッピングすることは困難であり、間違えやすいやり方である。アプリケーションを一連のステータスコードに「一致させる」ことは苦労を招くだけである。これはやってはいけない。

/foo リソースの 200 OKウィジェットが昇順に並んでいることを意味する」とか「ウィジェット404 Not Foundウィジェットが逆順であることを意味する」ということを述べようとしている仕様を見かけることは残念ながらよくあることである。これは、実際のところステータスコードのセマンティクスを再定義することである(汎用的ということを思い出して)。それによって、事実上、HTTP のプライベートバージョンを作成することになり、コードに悪い影響を及ぼす可能性がある(もともとそういう決まりがないのであれば)。

また、すべてのリソースと生成可能なステータスコードを一覧表示しようとする HTTP の API を見てきた。これはいい取り組みではあるが、悪いプラクティスである。クライアントが受け取るかもしれない一連のステータスコードは、彼らが把握しているひと握りの一覧より遥かに多いものである。これは、プロキシが設定されているかもしれないし、サーバーが 421 Misdirected Request429 Too Many Requests500 Internal Server Error を返す可能性があるためである。

代わりに、アプリケーションはメソッドやリソースの表現の観点からリソースの振る舞いを定義するべきである。例えば、

リンク形式で識別される foo のリソースは、application/foo+jsonapplication/bar といったフォーマットで表現でき、application/foo+json で PUT したり、application/json-patch+json で PATCH することでその状態を更新できる。

受け取るステータスコードは、すでに定義されており、広く知られている。一覧化したり、改良する必要はない。

POST のセマンティクスは特に汎用的であるため、特別なケースを示す。次に述べることは理にかなっている。

ウィジェットを並べるには、リンク形式で識別される foo リソースに application/example で POST し、成功時は Successful のステータスコード (2xx) で示される。

2xx 系のステータスコードは、成功を示すものとして使われることに留意する。それによって、将来のステータスコードとの前方互換性を保つことができる。

場合によっては、POST が固有のステータスコードを返すことを説明する必要があるかもしれない。例えば、新しいリソースを作成するために使われた場合、リソースの場所を示す Location ヘッダーとともに 201 Created を使う。あるいは、POST (または PUT) の処理がサーバーの状態と競合する可能性がある場合、409 Conflict を使う。ただし、これらはよくあることではない。

そして、もちろん、仕様には多くのサンプルを含めるべきである。

Specific Effects

これまでに述べたように、ステータスコードはレスポンスの具体的な作用を明らかにする。

例えば、301 Moved Permanently はリソースが移動したことをクライアントに伝えており、必要に応じて新しいリクエストで作ることができる。401 Unauthorized は HTTP の request authentication (※) の仕組みを使うきっかけになる。429 Too Many Requests はリクエスト数の上限であるため、落ち着くまでリクエストを止めることをクライアントに伝えている。
(※訳注: 日本語訳は こちら)

粗末な 404 Not Found であっても固有の処理がある。キャッシュがいわゆる「ネガティブキャッシュ」として機能することで(すなわち、ヒューリスティックな期限を割り当てられたもの)、Web クローラーのような自動的なエージェントは、リソースがすでに存在しないことを示すシグナルとしてそれを使用する。

これらの具体的な作用は、上記で述べた汎用的なセマンティクスに一致する。これは一般的な HTTP のソフトウェアによって処理されるためである。つまり、これらはアプリケーションに固有のものではなく、汎用的な HTTP スタック、例えば、キャッシュやクライアント、仲介者、場合によっては Web スパイダーによるものである。リソースのさまざな状態に関する情報が担うことは(「ここにある」「ここにはない」「向こうにある」とか)、それらが受け取るものとほぼ同じくらいアプリケーション固有のことである。(※)
(※訳注: このあたりの訳は自信がない...)

これらは、どの HTTP ステータスコードを使うか検討する際に考慮するべきことであり、アプリケーション固有のセマンティクスにどのようにマッピングするかということではない。特に、レスポンスの意図された処理が既存のステータスコードと同じ場合は、それを使うこと。

いくつかのステータスコードは、通常、HTTP レイヤーで自動的に処理されない。例えば、アプリケーションでリクエストが受け付けられたが、まだ処理はされてないことを示すために 202 Accepted を使うのであれば、それをドキュメントに記載した方がよい。

ここでも、固有の作用 (ステータスコード以外でリクエストが成功したかどうかを判断する必要があること) がすでに定義されているため、ステータスコードのセマンティクスを再定義する必要はない。代わりに以下を参照。

まして、それぞれのアプリケーションを HTTP ステータスコードに「深く」マッピングしようとすることは間違いであり、ほとんどの場合において、その粒度ははるかに粗い。疑わしい場合、適切なものがなければ、汎用的なステータスコードとして 200 OK400 Bad Request500 Internal Service Error を使っても問題ない。

Refining the Semantics of a Status Code

アプリケーション固有のセマンティクスは body に含めるのが適切である。ほとんどの場合において、使われるステータスコードを指定する必要はなく、「成功レスポンス」ということだけでおそらく十分である。HTTP ヘッダーを作成することもできるが、ここでは言及しない。

エラー (4xx5xx) の場合、自身で作成したくない場合は これらのフォーマット を使うことができる。

これに対する例外は、既存のステータスコードを利用する汎用的な HTTP の拡張機能を構築している場合である。例えば、新しい認証方式など。その場合、ステータスコードの仕様に記載されていることや、使おうとしている既存のヘッダーに留意する。これらは互換性を保つ必要がある。例えば、「511 Network Authentication Required というレスポンスの Location ヘッダーが意味するものは…」と書いてあっても、511 の仕様を更新しない限りこれは機能しない。

So You Want To Create a HTTP Status Code

これまで述べてきたことをすべて読んだ上で、それでも新しいステータスコードが必要であると思うのであれば、それはすべてのリソースに適用できる可能性があり、HTTP の実装に明らかな効果がある。既存のステータスコードで同様な効果があるものはない。そして、手続きを進める意思があるなら、これらの ガイドライン を読んでください。