restful web アプリの設計レビューの話
DESCRIPTION
RailsにおけるRESTfulなURL設計勉強会 千駄ヶ谷.rb #12 #sendagayarbTRANSCRIPT
RESTful Web アプリの設計レビューの話
和田 卓人 (a.k.a id:t-wada or @t_wada)July 23, 2012 @ sendagaya.rb
結論:REST は麻疹である
(良いものなので早く感染して厨期を卒業しよう)
自己紹介名前: 和田 卓人 (わだ たくと)
ブログ: http://d.hatena.ne.jp/t-wada
メール: [email protected]
Twitter: http://twitter.com/t_wada
タワーズ・クエスト株式会社 取締役社長
•WEB+DB PRESS vol.32「REST アーキテクチャスタイル入門」
•はてぶ設計議論
•DHH の RubyKaigi 2006 Keynote
•WEB+DB PRESS vol.38~「REST レシピ」
•『RESTful Web Service』
私と REST (input)
• Java でいろいろ実装 (JSR311関係)
•WEB+DB PRESS vol.42 「Restlet で動かしながら学ぶ REST の世界」執筆
•動画で配信!「現場で使えるREST」鼎談
•『Web を支える技術』トークセッション
私と REST (output)
おことわり:Rails の話はあまりしません
(REST の話ばっかりします)
•規模が大きい rails プロジェクト
• route 数 1000 以上
•レビューツール
•ホワイトボード
•チャット
•Wiki
• diff
URL 設計レビューを行ったプロジェクト
1. 対象となるデータを認識する
2. 対象となるデータをリソースに分ける
ひ (2 で分けたひとつひとつのリソースに対して)
3. リソースにURLで名前を付ける
4. リソースに対して統一インターフェイスのサブセットを提供する(GET/POST/PUT/DELETE をマッピング)
5. クライアントから受信する表現(Representation)を(一つ以上)設計する
6. クライアントに提供する表現を (一つ以上) 設計する
7. ハイパーメディアリンクとフォームを使用して、このリソースを既存のリソースに統合する (接続性 = Connectedness を高める)
8. 正常系を考える(適切なリクエストがあったとき何が起こるべきか)
9. 例外条件を考える(不適切なリクエストがあったとき何が起こるべきか)
RESTful アプリ設計のステップ
•URL 設計 (動詞、構造、クエリ)
• CRUD の重力に引かれていないか
•HTTP メソッドの選択
•ステータスコードの選択
•表現の設計
•情報量に過不足は無いか
•接続性を満たしているか
設計レビューで見るポイント
× GET http://example.com/blog/getEntries
○ GET http://example.com/blog/entries
× POST http://example.com/blog/entries/add
○ POST http://example.com/blog/entries
× POST http://example.com/blog/entries/30/delete
○ DELETE http://example.com/blog/entries/30
URL に動詞が含まれていないか
• add, delete, update => ×
• edit => △ (規約による妥協)
•なるべく名詞に近づける努力をする
• confirm -> confirmation
•名詞と動詞が同じ形のものは状況による
URL に動詞が含まれていないか
• Tumblr の奇妙な URL
• http://www.tumblr.com/show/everything/by/me
• それっぽく読めれば良いというものではない
• example.com/files/copy/:source/:destination => ×
• コピー先はコピー元と従属関係が無い(階層構造は不当)
• URL が右にいくに従って自然な階層構造/サブセットになっているか
URL が無理な構造になっていないか
• URL 設計のほとんどの時間は「名前を探す」ことに費やされる
• いつも辞書と共に設計する
• リソースとリソースの関係を表す第三のリソースを探す
• subscription, belonging, tagging
• リソースは DB レコードだけでは無い
• トランザクション
• 計算結果
URL が無理な構造になっていないか
• 「サーバ上の意味」と「どう見たいかという意思」
• “?” 以降をすべて取り去っても意味は変わらないか
• “?” 以前にリソースの意味と関係ない要素は無いか
URL の意味と意思
http://example.com/blog/entries?page=3&lang=ja
リソースの意味 クライアントの意思
•GET/POST/PUT/DELETE を DB の SELECT/INSERT/UPDATE/DELETE に “1:1 に自動的に” 対応させるのは思考停止
• 1:1 とは限らない
•多くの意味と表現を持つテーブルもある
•テーブルの重要度には濃淡がある
•従属的で個別の意味と表現を持たないテーブルもある
CRUD の重力に引かれていないか
•第3正規形のテーブルと 1:1 の route があるのは粒度が細かすぎる
•N+1 Problem にも容易に突き当たる
•リソースの粒度/視点(つまりは URL)とデータベースの粒度/視点の違いを解釈してしかるべく結びつけるのが Controller の仕事
CRUD の重力に引かれていないか
•URL で示されるリソースに対して「何をしたいか」で GET/POST/PUT/DELETE
•ここで揉めることは少ない
•GET 重要。とても重要。
•リソースを作る場合
•URL が新たに作成される場合は POST
•URL がわかっている場合は PUT
•どうにもならなくなったら POST に倒す
HTTP メソッドの選択
•意識的に使用するコードは概ね次のものに収束する
• 200, 201, 204
• 301, 303, 307, (304)
• 400, 404, 409, (401, 403)
• 500
•クライアント側が悪いときは 400 系、サーバ側が悪いときは 500 系
ステータスコードの選択
•例外系 (400/500系) は controller / model から投げる例外をステータスコードにマッピングする(これは rails の話)
•クライアントに対してリソースを隠匿するかどうかで 400 系を 404 に倒すこともある
ステータスコードの選択
•URL、あるいは URL の作り方(つまりフォーム)が含まれていること
•袋小路になっていないこと
•GET のパラメータを組み立てさせたいときはフォームを使う (フォームは POST のためだけじゃないよ)
• js 側で文字列を結合して URL を作るのではなく、 URI-Templates を渡す
• http://tools.ietf.org/html/rfc6570
表現の設計
• Content Negotiation
•Accept や Accept-Language ヘッダ
•表現のフォーマットは URL に含められるとなお良い
•表現の言語選択(ja,en,...)も URL に含められるとなお良い
表現の設計
• クライアントは、サービスから送られてくる表現の中に含まれているリンク(またはフォーム)を使用することによってのみ、自分の状態を変更できる(簡単な例を挙げるなら、リンクやフォームによってのみ、画面の状態を変えることができる)
• サービスは、クライアントがURLを組み立てることを強制してはならないし、期待してはならない
• サービスは、以上の点をクライアントに無理なく守ってもらうために、クライアントが次に取り得る状態をすべてリンク(またはフォーム)の形で表現に含める
接続性ある表現のために
議論
•やりたいこと vs. (Rails 的な)作りやすさ
•確認画面、プレビュー画面、完了画面…
•リソースの移動、コピー
•トランザクションの表現
•複数レコードを選択して更新する UI
• 207 Multi-Status の誘惑
議論になるポイント
•URL に機械採番の id が含まれる
•セキュアじゃ無い
•永続的でない(かも)
•API のバージョニング
•自前でやっていた• https://github.com/bploetz/versionist 良さそう
• rails4 の PATCH メソッドどうよ?
議論になるポイント
•あまり非同期処理に頼らない
•DOM Scripting の原則に従う
• RESTful なサーバとリッチ js という設計に倒しすぎると UX や保守性が低下する可能性があるので注意
• REST 厨がみんな通る道
•一方 Twitter はリッチ js から戻した
•制約をバランスすることこそが設計
議論になるポイント
参考文献
結論:REST は麻疹である
(良いものなので早く感染して厨期を卒業しよう)
ご清聴ありがとうございました
http://lumberjaph.net/graph/2010/03/25/github-explorer.html