0

httpリクエスト方式の話からRESTful webシステムのHttp Status code、URI設計、冪等性などについて

HTTPメソッドとしてGET,POST,PUT,DELETEがあります。
とりわけ、webサーバのアクセスログやアプリログなどでよくみる
リクエストの種類GET、POSTは運用者には馴染みなものですよね。

今回、この意味を誤解している人がいるようでしたので、
整理しようとおもいます。

webブラウザ上ではそれぞれの方式毎にリクエストパラメータの扱い方が異なります。

GET方式

GET方式は本来、名前の通り、webページ等の取得を要求するためのリクエスト方式です。
ハイパーリンクをクリックし、webサーバへリクエストする。
ブラウザのアドレスフィールドに入力し、webサーバへリクエストする。

上記アクティビティによるリクエストには入手したい資源の位置(URI)を記述しますが、
パラメータを含めることが可能です。

パラメータ文字列は”?”の後ろに記述し、複数ある場合は”&”で区切ります。
パラメータもURL文字と同じように扱われるため、表示されているし、ログにも残すことが可能です。
この事から、passwordを扱うには不向きな方式であることが判ります。

(例.) http://www.hachim.jp/servlet/?ID=hachim&password=123456789

POST方式

POST方式はサーバーに情報を送るためのリクエスト方式です。
パラメータはURIの一部分ではなく、リクエスト本体の一部分として送信されますので、
クライアントにおいては、パラメータの値は表示されません。
POST方式ではHTMLのFORMを使うことで、パラメータを送信することができます。

http://www.hachim.jp/technote/difference-between-post-and-put.html

ここで、HTTPメソッドに関して、解像度をあげるべく、
RESTfulなWebサービスにみるHTTP、リソース設計、HttpStatusCodeの動きをみていきましょう。

REST方式でない通常のWebアプリケーションでは、通常HTTPステータスコードとしては200(OK)しか返されません。
エラー等の状態を表す場合でもHTTPステータスは200(OK)が返され、画面に表示される内容にエラーを表すメッセージ等を含ませる事によって状態を表現します。

RESTfulなWebサービスを実現する場合には、処理結果はHTTPステータスコードで表現するべきとされています。
理由としては、以下のものがあげられます。
適切なHTTPステータスコードを返さない ( 全部 200 (OK) とかの ) 場合、エンティティの中身を解析しなければ、処理結果が判別できない。
Web標準に従う事で、HTTPステータスコードから処理結果がどうだったのか理解できる。(少なくとも理解しやすい)
HTTPステータスコードだけで、処理結果の詳細 ( エラー内容等 ) を表現できないという意見も出そうですが、これら詳細情報はエラーが発生した場合のエンティティに詳細情報を含ませる事で解決できます。

まず、HTTPステータスコードで判定し、ステータスコードに応じてその後の処理を振り分ける方が明らかに効率的ですし、Webサービスのような他システムから利用されるサービスにおいては適切な実装方法と言えるでしょう。

HTTP Status Code

RESTful なWebサービスを構築する場合に、処理結果に応じてHTTPステータスコードを使い分けるのは分かったけど、どういった場合にどういったコードを使えばいいのかは判らない。
rest-httpstatus-diagram

とあるサービスの例ですが、

リソースの操作 (CRUD) に応じてHTTPメソッドを使い分ける

旨記載されています。

リソースの作成に関しては POST ではなく PUT を利用しても構いません。

但し、この場合も

POST, PUT のどちらを使うべきかという指針

は存在します。

この指針は判りにくいのか、説明してもすぐには理解してもらえなかったり、
プロジェクトの中でも誤った利用の仕方をされる場合が結構あるので、ここに書いてみます。

べき等

POST と PUT も含めたそれ以外のHTTPメソッドの大きな違い。
それは 『べき等』 であるか否かです。

※漢字だと 『冪等』、あるいは、『巾等』 とも書く
元々は数学の用語で、

『ある操作を何度行っても同じ結果になる場合、この操作はべき等』

であるといいます。

各HTTPメソッドのべき等性

HTTPメソッド べき等性
POST べき等でない
PUT べき等
DELETE べき等
GET べき等

GET はもともと副作用がないメソッドとして定義されており、あるURIに対して、
何度GETを繰り返してもリソースの状態は変化しない事が保証されています。

DELETE も GET に次いで判りやすいでしょう。
一度削除しても、複数回削除しても、削除された状態が変わる事はありません=べき等

では、POST と PUT は?

リソースの新規作成で考える

例えば

社員管理システムをRESTful Webサービスで作成する事を考えます。

(無論、RESTfulでないwebはレスポンスコード設計の概念がないので。。。)

社員リソースの URI は以下になります。
http://<サーバ名>/employee/<社員番号>
社員リソースの作成には以下のXMLを利用するとします。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
  <first name>太郎</firstname>
  <lastname>ハチエム</lastname>
   ・
   中略
   ・
</employee>

Webサービス側では、上記XMLをもとに” ハチエム太郎 “さんの社員リソースを作成します。
この場合、以下のような二種類のシステムが考えられます。

①社員番号をシステムが自動付与するシステム
②社員番号はシステム外で決定し、リソース作成時にこの値を指定するシステム

上の①のシステムにおいては、XML、及び、作成を行うための URI に社員番号は含める事ができません。
同一の XML を利用しても、作成のための処理が行われる度、社員番号が変わります。
これはべき等ではありません。
つまり POST メソッドを利用するのが適当と言えます。
データ保存にDBを利用していて、ID をシーケンスや AUTO INCREMENT にしている場合はこのケースになるでしょう。

一方②のシステムにおいては、システム外で ID を決定後にリソース作成を行うため、
何度作成処理を行っても同一のリソースが作成される事になります
( 2回目以降は、同一データで上書きされる、あるいは、既にデータ作成済みとして処理がされない。
いずれにしてもリソースの状態は同じになる )
これはべき等になります。
この場合は PUT メソッドの利用で問題ありません。
※①の場合と異なり、新規作成を行うURIにも社員番号を含める事ができます。

リソースの新規作成のメソッドとしてはべき等ではない POST を利用しています。
CRUD以外の処理ではどうか

一般的なCRUD以外の処理ではどうでしょうか。
簡単な口座振り込み処理を考えてみます。
内部処理としては以下のような二種類の処理があったとします。( 実際にあるか/適切かは別として )

A口座からB口座へお金を移動する処理を行う。
A口座、及び、B口座の金額を振込後の金額に設定する処理を行う。
この処理の事前処理として、A口座、B口座の残高は確認しておく。
①の処理の場合には、複数回実行されれば、そのたびお金が移動します。=べき等ではありません。
②の処理の場合は、金額を設定する処理に関していえば、同じリクエストが何回発行されても、A口座、B口座の残高は同じになります。=べき等です。

べき等に関わる宗教論争

POST、PUT ( あるいはPOST以外 ) の使い分けを行うにあたっては、
上記のようにべき等性がどうであるか考えて決めるべきとされているのですが、
以下のようなケースはどうなるのでしょうか?

リソース取得であるが、アクセスを記録しており、アクセスログレコードが新規作成される。
同一データで更新リクエストがされた場合でも、最終更新日時を保存している。
GETリクエストを複数回行った場合に、利用者側から見たリソース変更はなくても、システム内部では変更が生じています ( 副作用が発生している )。
最終更新日時を保存しているシステムは結構多いと思います。
リソースの更新は普通に考えると PUT ですが ( 最終更新日時以外はべき等になる )、POSTにすべきでしょうか?
こういった場合、
べき等性が崩れているからGETではない。POSTにすべき。
→ 反論 : でも、全てのリソースのアクセスログとってたら、GETなんて使えないじゃん?
利用者側からみたらべき等だからGETで問題ない。リソース取得でPOST!?アホか!!
→ 反論 : いや、実際リクエストの度にリソースに変更が発生するんだから、べき等ってはいわないでしょ?
最終更新日時を保存する時点でべき等ではないからPOST!
→ 反論 : この場合も、ほぼ全てのリソースでPUTは利用できなくなる。。。
など、人によって考えは色々で、べき等 ( および、HTTP、REST ) に関する宗教論争になってしまう可能性があります。
私自身は、 『リソースの本質に変更がなければ、完全にはべき等でなくてもPOST以外のメソッドで構わない。』 という考えで使い分ける事にしています。
更新日時やアクセスログが変わったからといって、その他の内容に変更がなければ 同じリソース=リソースに変更はない=べき等 として構わないだろうという事です。

まとめ

べき等に関しては、上述のとおり、『これが絶対正解!!』といったものにはお目にかかった事がありません。
人によって考え方が異なり、面倒臭い論争に巻き込まれる可能性もあるかもしれません。
但し、これといった正解がないからといって、何も決められないわけではありません。
サービスを構築/実装する場合には基本的な指針は決めておいた方がよい事は間違いないでしょう。

今回の話

ステータスコード
詳細なエラーコードをどうクライアントに伝えるか?
リソースURI
URIもちゃんと決めないと、後でもめたり、はまったりする
等は、初めにきちんと設計するか、あるいは、ある程度しっかりした指針がないとカオスになる可能性があります。
きちんと考えて利用者/開発者双方にやさしいサービスが作れるといいですね

CRUD(クラッド)
wikiより抜粋
ほとんど全てのコンピュータソフトウェアが持つ永続性の4つの基本機能のイニシャルを並べた用語。その4つとは、Create(生成)、Read(読み取り)、Update(更新)、Delete(削除)である。ユーザインタフェースが備えるべき機能(情報の参照/検索/更新)を指す用語としても使われる。

各HTTPメソッドがリソースに対するCRUD操作に対応しています。

HTTPメソッド CRUD操作
POST CREATE (リソースの新規作成)
PUT UPDATE (リソースの更新)
DELETE DELETE (リソースの削除)
GET READ (リソースの参照)

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です