yohei-y:weblog

XML と REST/Web サービス関連の話題が中心の weblog です

2007-06-18

HTTP ステータスコードを正しく使おう

先月、ぐるなび API がリリースされていました。 ぐるなびさんの持っている膨大なデータベースに Web API を通して気軽にア クセスできるようになったのは、非常に喜ばしいし、その英断に感謝したいと 思います。

しかし、Web API 仕様書、特にエラー仕様を見てちょっとがっかりしました。 もう少し上手にデザインすれば、もっとよかったのに…、という思いです。

一度出してしまった API はそう簡単に変えられないと思いますが、 参考までに僕だったらどうするか、を書いてみます。

この仕様の一番の問題はエラーコードです。 以下は 2-2 のエラー仕様に記述されているサンプルです。

<?xml version="1.0" encoding="UTF-8"?>
<gnavi>
 <error>
   <code>602</code>
 </error>
</gnavi>

タグが三つ(gnavi, error, code)出てきます。 重要なのは code だけで、ここにエラーコードが入ります。 602 というコードは Invalid Shop Number を示します。 エラーコード一覧を見ると、現在五つのコードが定義されていることがわかり ます。

よくない点を一言で言うと、エラーコードを再発明してしまっているということです。 たとえば 604 は "Internal Server Error" なんですが、 このフレーズに覚えがありませんか? そう HTTP の 500 Internal Server Error と同じです。HTTP で 500 を返せばいいところを、 独自 XML 形式でしかも 604 という独自のエラーコードを再発明しています。

HTTP/1.1 200 OK
Content-Type: application/xml

<?xml version="1.0" encoding="UTF-8"?>
<gnavi>
 <error>
   <code>604</code>
 </error>
</gnavi>

本来はこうあるべきです。

HTTP/1.1 500 Internal Server Error
Content-Type: text/plain; charset=utf-8

処理中にエラーが発生しました。

なぜエラーコードの再発明は駄目なのでしょうか。それは専用のクライアントが必要になる からです。単なる HTTP クライアントではなく、ぐるなびのエラーコードを実 装した専用クライアントが必要になってしまうからです。専用クライアントが 必要なので、その分余計なコードが必要となって、障害が発生する確立も上り ます。

参考までに、ぐるなび API のエラーコードを HTTP のステータスコードにマッピングしてみました。

gnavi エラーコードHTTP ステータスコード
600 NoShop404 Not Found
601 Invalid Access403 Forbiddden
602 Invalid Shop Number400 Bad Request
603 Invalid Type400 Bad Request
604 Internal Server Error500 Internal Server Error

601 は通常は 401 Unauthorized にしたいところですが、 ぐるなび API は api key 方式を採用しているので 403 にしてみました。 また、この対応により 602 と 603 が 400 にまとめられてしまっていますが、 両者の違いは HTTP のレスポンスボディで記述すればいいでしょう。 もし、この二つを区別する理由が、エラーメッセージを出すためだけであれば、 メッセージそのものをプレーンテキストで返せばいいのです。

HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8

指定された店舗の情報が存在しません。
HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8

不正なぐるなび店舗IDパラメータが指定されました。

WEB+DB Press の今月号には、まさにこの話を書きました。 本文とコラムが同じくらいのページ数という、一時期の JavaWorld の檜山さ んみたいな構成ですが、 普段なにげなく使っている HTTP のステータスコードは Web API を作る上でどうあるべきか、という話です。

photo
WEB+DB PRESS Vol.39
WEB+DB PRESS編集部
技術評論社 2007-06-22

ラベル: , ,

8 Comments:

At 2007年6月19日 9:58:00 JST, Anonymous 匿名 said...

WebAPIに関わらず、通常のシステム開発でもよくあることですね。

IllegalArgumentExceptionがあるのにParameterExceptionを作っているフレームワークとか。
勘弁してよって。

 
At 2007年6月19日 11:08:00 JST, Blogger Unknown said...

ぐるなびのAPIは自分もそう思いました。設計慣れしていない雰囲気を感じます。

IllegalArgumentExceptionは実行時例外なので、キャッチ例外が欲しいという可能性があるかも。

 
At 2007年6月21日 0:25:00 JST, Blogger Unknown said...

主題には同意しますが、エラーメッセージはこれがいいのでしょうか?
・本文にエラーコードを入れる。
・本文のエラーの説明には、英文は必ず入れる。
・もし日本語だけにするならば、せめて言語タグを入れる。
方が良いと思いますが。

 
At 2007年6月21日 21:45:00 JST, Blogger yohei said...

Akihiro さん

HTTP レスポンスボディを plain text にしたのは簡単のためです。利用しているメッセージフォーマットに合わせて text, xhtml, atom entry, 独自 XML などを適宜適用するのが望ましいと思います。

ただ、その中にエラーコードが必ず必要とは思いません。どんなユースケースを想定されていますか?

 
At 2007年6月22日 12:07:00 JST, Blogger Unknown said...

簡単のため、というのは説明を簡単にするため、という意味ですか?

以前から海外のサービスで、エラーメッセージが現地語(ドイツ語とか)しかないものがあり、せめて英語のメッセージも併記してもらいたいとおもっていましたので、英語のエラーメッセージは併記して欲しいですね。

また、エラーコードの件はシェルスクリプトからwgetを使ってアクセスして、エラーの場合コードを検出して分岐する、なんて事例を想定しています。

 
At 2007年6月22日 16:54:00 JST, Blogger yohei said...

「簡単のため」はそのとおりです。

エラーメッセージの多言語化ですが、クライアントが Accept-Language ヘッダで自分が所望する言語を指定することも可能です。この場合はクライアントの要求に合わせた言語のメッセージを plain text で返してもいいですね。もちろんサーバ側で実装する必要があるわけですが。

wget の例、ありがとうございます。ただ、まだちょっとわかりません。その分岐には本当にステータスコード以外のエラーコードが必要ですか?ぐるなびの例でいえば、invalid shot number と invalid type のコードがレスポンスに入っていたとして、wget は何をどう分岐するんでしょう?

 
At 2007年6月23日 0:57:00 JST, Blogger Unknown said...

エラーメッセージの言語の例は、Accept-Languageが指定されていない場合は英文のエラーメッセージで、指定されていたらその言語で、という仕様ならば問題ありません。

あと、エラーコードの件は、HTTPのステータスコード以外のエラーコードを付けるべきだ、とは主張していません。
エラーメッセージの部分(できれば先頭)にHTTPのステータスコードが書いてあれば、より便利と主張しているだけです。

 
At 2007年6月29日 23:52:00 JST, Blogger yohei said...

エラーメッセージ(HTTP レスポンスボディ)に HTTP ステータスーコードを書いて、そのコードで処理を分岐するのには反対です。ステータスコードは HTTP の仕様どおり、レスポンスのステータスラインに書かれているものを前提に処理を行うべきです。メッセージにエラーコードが書かれていなかったらどうするんでしょうか。結局ステータスラインを見ますよね。

 

コメントを投稿

<< Home