Webで成功するサービスを作る究極の指針は「シンプルであること」だと思います。これは別にWebに限らずそうだと思います。例えば、AppleやSONYやDELLなどの起業が成功したのは、シンプルな製品、サービスを作り出したからではないかと思います。Googleの検索窓なんかは、究極のシンプルだと思います(だんだんといろんなものがつき始めましたが。。。)
業務で使用するWebサービス、コンシューマ向けのWebアプリケーションAPIなどもこの設計指針が当てはまると思いますし、本書はこのことだけが追求されて書かれている良書です。
Webの成り立ち、ここまで成長してきたのは何故か、Webをより良く使うための設計方針が本書には詰まっています。Web開発の初心者にはもちろん、Web開発をバンバンにやってきた人にも、一度は目を通して欲しい本です。かなりオススメですし、読めば必ず目から鱗間違いなしです。
RESTについては、RESTful Webサービスの記事も参考にしてください。
Webを支える技術
- HTTP、URI、HTML
HTTPというシンプルなプロトコルの上で、リソースを一意に特定するURIを用いて、HTMLで記述されたメディアを読む。Webはそんなシンプルな技術によって成り立っています。
- ハイパーメディア
テキスト、画像、音声、動画などをハイパーリンクで結びつけたシステムをハイパーメディアと呼びます。Webで最も重要なのはこのハイパーリンクによってメディアがリンクしているということです。
- 分散システム
Webはひとつのシステムで成り立っているわけではなく、大量のコンピュータが組み合わさっています。ネットワーク上に散らばったこれらのコンピュータが相互動作するのは、シンプルなプロトコルだからこそと言えるでしょう。
REST-Webのアーキテクチャスタイル
RESTとはアーキテクチャスタイルでRESTアーキテクチャスタイルなアーキテクチャのことをRESTfulアーキテクチャと呼びます。
RESTはWeb全体のアーキテクチャスタイルでもあり、個別のWebサービスやWeb APIのアーキテクチャスタイルでもあります。一人一人が作る個別のWebサービスやWeb APIでも、RESTの約束を守ることが重要です。個別のWebサービスが全体の調和を乱しては、全体が統一したアーキテクチャスタイルを守れないからです。
リソース
RESTの重要な概念の一つにリソースがあります。リソースとはWeb上に存在する名前を持った情報の事をいいます。WebではこれをURIで表します。
RESTfulアーキテクチャではこのリソースを「アドレス可能な状態」にしておくことで、システムとして綺麗な形(シンプルなプログラムが可能)になります。
URIが備える、リソースを簡単に指し示せる性質のことを「アドレス可能性」(Addressability)と呼びます。リソースをアドレス可能な状態、すなわちきちんと名前が付いており適切な手段でアクセスできる状態にすると、プログラムをとても作りやすくなります。
リソースは複数のURIを持つことができます。例えば、
http://www.hamasyou.com/reports/newest
http://www.hamasyou.com/reports/system/2010-05-31/1
は同じリソースを指すことができます。ただし、一つ目のURIは時間の経過とともに指し示すリソースが変わってしまうことがあります。常に同じリソースを表したい場合には、パーマネントリンクなどを参考にすると良いでしょう。
クールなURIは変わらない
良いURIやきれいなURIの事を「クールURI」と呼ぶそうです。「URIが変わらないべきである。変わらないURIこそが最上のURIである。」
クールURIにするためには、次のことに気をつければ良さそうです。
- プログラミング言語に依存した拡張子やパスを含めない
- メソッド名やセッションIDを含めない
- URIはリソースを表現する名詞にする
プログラミング言語に依存した拡張子やパスを含めない
例えば、JavaのStrutsを使うと、スタンダードなURIは「.do」という拡張子がつけることが多くあります。また、CGIなどの場合には、スクリプト言語の拡張子(.pl、.rb、.cgi など)をそのまま使うことがあります。
また、CGIなどの場合、「cgi-bin」などのディレクトリ名をパスに含めることがあります。これもプログラミング言語に依存したパスを含めていることになります。
こういった、プログラミング言語のデファクト、パス情報、ファイル拡張子などをURIに含めないようにすると、URIが変わりにくくなります。
メソッド名やセッションIDを含めない
リソースに対する処理メソッド名をURIに含めると、使っているフレームワークや仕様変更によりURIが変わりやすくなってしまいます。また、セッションIDなどをURIに含めるとアクセスする度にURIが変わってしまいかねないという状況になってしまいます。
http://www.hamasyou.com/sample/execute?cmdName=showPage&page=3;jssessionid=1234567890
URIにはメソッド名やセッションIDを含めないようにすると良いです。RESTfulアーキテクチャでは、統一インターフェースとしてHTTPのメソッド(GET, POST, PUT, DELETE)を使用すると良いでしょう。
URIはリソースを表現する名詞にする
URIにはメソッド名を含めずに、HTTPメソッドを使用して処理を分けると良いです。
悪い(×): http://www.hamasyou.com/show/articles?id=10 (POSTでアクセスする)
良い(◯): http://www.hamasyou.com/articles/10 (GETでアクセスする)
URI設計のテクニック
拡張子で表現を指定する
ここまで、拡張子はURIの設計にとって悪であると述べてきました。しかし、悪いのは「.cgi」や「.pl」など実装に依存した拡張子です。実装に依存していない拡張子は良い側面を持つ場合もあります。
- 言語を指定する拡張子
- 言語を指定する拡張子「.ja」「.en」をリソースに含める。
- フォーマットを指定する拡張子
- 「.html」「.atom」「.xml」「.json」などの表現フォーマットを指定する拡張子をリソースに含める。
その他
統一インターフェース
- GET
- リソースを取得する場合に使う。冪等(べきとう)。
- POST
- リソースを作成するときに使う。レスポンスとしてリソースのURIを返してくれることを希望する(新規作成の場合など)。新しいリソースのURIはLocationヘッダで返される(POST後はリダイレクトされる)。冪等ではない。
- PUT
- リソースを更新するときに使う。リソースのURIは変わらない。冪等だがリソースの状態は変わる。
- DELETE
- リソースを削除する時に使う。リソースのURIがわかっている場合に使い、なんど呼び出しても結果は変わらないべき。つまり、存在しないリソースに対してのDELETEは何もいわずに成功するし、DELETEによって他のリソースのURI表現が変わることはないようにする。冪等。
検索結果にリソース表現
http://www.hamasyou.com/articles/search?q={query}
searchというメソッド名をURIを含めているじゃないかと思うが、そうではなく、これは検索結果というリソースを表している(searchは名詞の方の検索)。
オブジェクトモデルにおける関連のリソース表現
関連のどちらがトップレベルリソース(上にくるリソース)かを考え、URIの階層構造でURIを表す。
記事群-設計カテゴリ-最新記事の場合。
http://www.hamasyou.com/articles/system/newest
設計カテゴリ-記事群-最新記事の場合。
http://www.hamasyou.com/system/articles/newest
ロック機構をリソースで表す
Web APIによってはロック機構を組み込みたい場合があります。この場合は、ロックを表す子リソースを作ることで対応できます。
リソースに対して、ロックリソースを作成し、そのロックリソースをDELETEすることでロック解除を表す。
本書 P.289より抜粋。
POST /1120034 HTTP/1.1 Host: zip.ricollab.jp Content-Type: application/x-www-form-urlencoded Authorization: Basic ... scope=exclusive&timeout=300
ロック用のパラメータをリソースに対して送信し、ロックリソースを作成する。
HTTP/1.1 201 Created Location: http://zip.ricollab.jp/1120034/lock Content-Type: application/json { "locktype": "exclusive", "timeout": "2010-09-07T10:00:30Z", "owner": "yohei" }
ロック解除は、POSTで作成された子リソース(lock)を削除することで行う。
DELETE /1120034/lock HTTP/1.1 Host: zip.ricollab.jp Authorization: Basic ...
HTTP/1.1 200 OK