リソースモデリングパターンをまとめています。
Webアプリケーションについて、RESTfulなURL・リソース設計のパターンを見出すことで、
ということを目指しています。
- ほんとうに役立つか
- これはパターンと言えるのか
- もっと他にもある
- だいぶ粒度がバラバラ
- 名前の付け方(パターンは名前重要)
など、ぜひご意見をください。
パターン
Collection & Member Resource パターン
Singular (Singleton) Resource パターン
Filtered Collection パターン
Filtered Subresource パターン
Multi-member Resource パターン
Partial Resource パターン
Transaction Resource パターン
Session Resource パターン
Private Resource (Namespace) パターン
Implicit Collection パターン
リソースの大分類
URL(パス)の構造を目安として分類したものです。
コレクションリソース
→ Collection & Member Resource パターン
メンバーリソース
→ Collection & Member Resource パターン
単数 (Singular, Singleton) リソース
→ Singular (Singleton) Resource パターン
補助リソース
→ Collection & Member Resource パターン
アルゴリズムリソース
静的リソース
- 画像とかJavaScriptとかCSSとか
- もともとWebに静的・動的の区別があるわけではないので、Railsや、Webアプリケーションフレームワーク特有の分類かもしれない
- GETのみ
ルートリソース
- 他のリソースへのナビゲーション的役割 (GETのみ)
- もしくは、サービスの主となるリソース (コレクションリソースが多い)の別名
Implicit Collection パターン
/{id}
どのようなパターン?
Collection & Member Resource パターンから、コレクションリソースの部分を取り去ってパス階層を縮めた形。
例えばこのようにする。
/users/1/articles → なし /users/1/articles/2 → /users/1/2
コレクションリソースを省略する理由としては、
- コレクションリソースが不要
- コレクションが何であるかは自明
- パスを短くしたい
などが考えられる。
コレクションリソースが不要
「コレクション全体」へのアクセスが必要ない場合。 TwitterやGitHubは、ユーザー数が膨大で「ユーザー全体」というリソースを提供する意味がなく、個別のユーザーリソースだけがあればよい。
/users/tkawa → /tkawa
別のリソースを作る場合、ユーザーリソースの名前と衝突しないように注意。
また、Factoryの役目を担うリソースがなくなるため、リソース作成の手段を考慮する必要がある。
コレクションが何であるかは自明
年月日の例。
/years/2012/months/12 → /2012/12
ルートリソースを代用
/users/tkawa → /tkawa
のように最初のパス階層を省略するときは、ルートリソース/
をコレクションリソースとして使うことも可能。
Rails routes.rb の書き方
resources :users, path: ''
Private Resource (Namespace) パターン
/my /my/{resource}
どのようなパターン?
Singular Resource パターンの特別な場合で、「自分自身」を指すリソース。
人(セッション)によって違うリソースを指すことを明示するために名前空間を分ける、という用法に着目する場合は、Private Namespace パターンとも呼べる。
Rails routes.rb の書き方
resource :my do resources :posts end
もしくは名前空間的用法
namespace :admin do resources :posts end
コラム:/my
って変?
/my
というURLはちょっと奇妙に感じるかもしれません。/my/posts
だとわかりやすいのですが。
/me
を選ぶ場合もあります。しかしその場合/me/posts
がちょっと奇妙です。
どちらを選ぶかは好みですが、どちらかに統一するのがよいでしょう。また、/my/posts
だけが存在して/my
が存在しないのは、あまりよくありません。
Session Resource パターン
PUT /session (→ログイン) DELETE /session (→ログアウト)
どのようなパターン?
認証のセッション自体をリソースととらえる。Railsでいう「モデル」ではないリソースの典型例。
Railsの認証Gemを使った設計例ではすでに一般的に採用されている。
- Devise
- Sorcery
- OmniAuth
リソースの分類からみる
上記の例だと単数リソースで実現されている。さらに自分に紐付いているものであるとみなして、
PUT /my/session (→ログイン) DELETE /my/session (→ログアウト)
とすると Private Resource パターンとなる。ただしログイン前から /my
が存在するのは少し不自然かもしれない。
コレクションリソースを使って
POST /sessions (→ログイン) DELETE /sessions/{id} (→ログアウト)
と実現することもできるが、こうした場合のid
は何なのかよくわからない。
Transaction Resource パターン
POST /transactions ↓ PUT /transactions/123 ↓ PUT /transactions/123/committed
「Webを支える技術」p278より引用
実際のシステムでは、より複雑な処理、たとえば複数のリソースにまたがった変更をひとまとまりに扱う、いわゆるトランザクションが必要になるケースもあるでしょう。
主にCollection & Member Resource パターンを用いたトランザクションの実装。
ウィザードなどにも適用可能で、モデルでないリソースになりうる。
例
http://qa.atmarkit.co.jp/q/2555#answer_15110 の id:moro さんの回答より引用
やり方はいろいろありますが、データインポートなど複数のリソースに影響を及ぼす、バッチ的な動きをさせたい場合には「トランザクションリソースを作る」という考え方でリソース設計するようにしたところ、いろいろ捗りました。
たとえば今回の例でも「インポート処理: import_job」を作るという風に考えると、ルーティングは
resouces :import_jobs
としておき、
GET /import_jobs/new (ImportJobsController#new)
でインポート用のフォームなどを表示し、POST /import_jobs (ImportJobsController#create)
で実際のインポート処理をはじめるなど、いろいろやりようがあります。私が実アプリで取り組んだときは、インフラの都合上非同期にインポートジョブを実行させたかったので、createアクションの中でいったん必要な情報をDB(import_jobsテーブル)に保存しました。その後でワーカーに流し、
GET /import_jobs/:id
で進捗状況や実行結果を表示という作りにしました。ポイントは『処理の固まり』を作るのもリソース作成としてとらえることです(なんでもかんでもやると妙ちくりんですが)。
Partial Resource パターン
/users/123/name,email /users/123?fields=name,email
リソースの部分取得、部分更新のために一部の属性(フィールド)だけを提供するもの。
Multi-member Resource パターンと形が似ているが、Multi-member Resource パターンは複数のメンバーリソースを列挙するものであるのに対し、Partial Resource パターンは1つのメンバーリソースのさらに一部分を取り出すものである。
通信量に制限のある環境などで有用。
使用メソッド
GET, PUT, DELETE
Multi-member Resource パターン
/users/123,124 /users/123-133
メンバーリソースの派生形。複数のメンバーリソースを一度に取得、更新、削除するために使用できる。
前者の列挙型であればどんなIDでも利用できるが、後者の範囲型は数値などの限られたIDでしか利用できない。
使用メソッド
GET, PUT, DELETE
ステータスコード
一部のリソースだけ更新・削除に失敗したとき、 207 Multi-Status の使用を検討する。