RESTful API のおさらい
前後リンク
- RESTful API のおさらい
- Rails での JSON API 実装まとめ
- スキーマファースト開発
- The NEXT of REST
REST の歴史
REST (REpresentational State Transfer) という言葉は 2000 年に Roy Fielding の博士論文で初出しました。
(思想としてはその前からあった? REST 入門)
日本では 2005 年ぐらいから徐々に流行りだして、 2006 年に WEB+DB Press で特集や連載が組まれる等が行われ、 (Rails 2.x が RESTful を打ち出した) 2007 年の終わりには web 開発者の間では一般化した言葉になっていたって印象。
なぜ REST が必要になったのか
はるか昔はメインフレーム上で全部入りのアプリケーションを開発していたので何も問題はなかった。
異ベンダーのアプリケーション間で連携を取るようになり、 また、クライアントサーバモデルというシステム構成が普及。
通信インタフェースの適切な手法が求められた。
そこで RPC (Remote Procedure Call) って話になり SOAP や WSDL、WS-* といった技術が出てくるんだが、 その流れに乗らずに「HTTP、URI といった Web 標準を上手に使えば大丈夫」という人が現れる。
これが REST の始まり。
Web 標準を上手に使い、REST の原則に沿ったアプリケーションにしていると
- シンプルな設計になり
- 直感的に使いやすく
- 開発もしやすい
ものになる。
SOAP みたいな RPC は何でもできるけど重厚なので最近は (少なくとも web 系では) 落ち目。
余談だけど「Web サービス」って言うと SOAP の文脈の方の Web Service かと思っちゃうので なるべく「Web アプリケーション」と呼称したい派です。
REST を 3 行で言うと
- アプリケーションの設計方法の一つ
- 操作の対象となる「リソース」を URI を使って表して
- HTTP メソッドを使って操作する
例えばどういうこと?
この記事を見るのにはブラウザだと URL を開くが、telnet からだと
> telnet blog.onk.ninja 80
GET /2017/09/21/review_of_restful_api HTTP/1.1
Host: blog.onk.ninja
を実行する。
ブラウザで URL を開く場合、これと同じことをブラウザがやってくれている。
http://blog.onk.ninja/2017/09/21/review_of_restful_api
という URL で表される「記事」リソースを
HTTP の GET
メソッドを使って取得している。
記事の削除も似たようなノリで、リソースを表す http://blog.onk.ninja/2017/09/21/review_of_restful_api
という URL に対して DELETE
メソッドを使う。
HTTP method とステータスコード
HTTP メソッドと CRUD
CRUD に対応する HTTP メソッドはそれぞれ以下の通り。
HTTP method | CRUD |
---|---|
POST | Create |
GET | Read |
PUT | Update |
PATCH | Update (部分更新) |
DELETE | Destroy |
ステータスコード
REST は「Web 標準を上手に使う」アーキテクチャなので、ステータスコードも大事にする。
status code | 意味 |
---|---|
2xx | Success |
3xx | Redirection |
4xx | Client Error |
5xx | Server Error |
- リソースの作成が成功した時は
201 Created
を返す - リソースが存在しない時は
404 Not Found
を返す
等、よく使うものは決まっているので覚えちゃいましょう。
resource とは
取得する単位。もの。
ものを表すので、名詞になる。
例えば「User と Friend になる」を「User 間の Friendship を生成する」に読み替える等、 慣れがないと見つけるのが難しいものもある。
(この場合、リソースは User と Friendship)
リソースの URI の作り方
まず、「名詞をリソースにして」「リソースの CRUD を HTTP Method で表現する」ということから、 URI には動詞は含まれない ということを意識する。
あとはリソースの本質を表す形になっていれば問題無い。
本質では無いもの、例えば
- 状態 (
latest
とかold
とか。リソースの状態は変化する) - 作者名 (組織が管理しているリソースの場合、転職等で容易に引き継ぎが発生する)
- 拡張子 (内部システムを切り替えると URI が変わるなら本質ではない)
等が含まれないようになっているとより望ましい。
この辺りは Hypertext Style: Cool URIs don't change. を参照。 日本語訳:クールなURIは変わらない -- Style Guide for Online Hypertext
なお、クールな URI の話が出てきたのは 1998 年で、当時は
検索フォームが POST で実装されているので検索結果の URI が無いとか、
すべて /servlet.do?type=book&id=1
のようにクエリパラメータだけで表現したりとかといった URL が
氾濫していたので、これを「ふつう」にしていこうって動きがあったことを念頭に置いて読むと良いと思う。
今ではあまり異常な URL は見ないので、意識しなくても自然な設計ができるかもしれない。
Rails と REST
Rails v2.0 (2007年12月リリース) で、リリース文に入ってくるぐらい強く RESTful を打ち出している。
We’ve got a slew of improvements to the RESTful lifestyle.
Riding Rails: Rails 2.0: It's done!
v5.1.4 現在では
Rails.application.routes.draw do
resources :books
end
と resources
を設定すると、以下の 7 action が定義される。
(PUT
と PATCH
は両方受け付けているが、どちらも update
処理)
Prefix Verb URI Pattern Controller#Action
books GET /books(.:format) books#index
POST /books(.:format) books#create
new_book GET /books/new(.:format) books#new
edit_book GET /books/:id/edit(.:format) books#edit
book GET /books/:id(.:format) books#show
PATCH /books/:id(.:format) books#update
PUT /books/:id(.:format) books#update
DELETE /books/:id(.:format) books#destroy
/books
という URL が book の集合 (/books/1
, /books/2
, ...) を表しているので
/books
への GET で集合が取得できるし、/books
への POST で新しい book を追加できる。
/books/:id
に対する GET, PUT/PATCH, DELETE は見たまんまですね。
new
と edit
ところで
HTTP method | CRUD |
---|---|
/books への GET | book 一覧の Read |
/books への POST | book の Create |
/books/:id への GET | book の Read |
/books/:id への PUT/PATCH | book の Update |
/books/:id への DELETE | book の Destroy |
はまぁ分かるとして、new
と edit
はいったい何なんだ、動詞は使うなって言ったじゃないかって話になると思うが、
これは「REST の原則からは外れるけれど一般的なアプリケーションには入力フォームを表示するページが必要だよね」って
Rails が勝手に作ったデフォルトなので深く気にしないように。
どう考えても無いとツラいものは現実を見て妥協するしかない。原理主義に陥りすぎないこと。
また、例えばいわゆる「コメント欄」では一覧画面に新規作成フォームを入れてしまうのをよく見るし、そうすると
new
が不要になるので、この 7 つが 必須 というわけでもない。
ちなみに api mode だとこの 2 つは作られなくなります。
nested resources
リソース間に親子関係が存在することがある。
class Group < AR::Base
has_many :users
end
class User < AR::Base
belongs_to :group
end
このようなリソースのルーティングは
resources :groups do
resources :users
end
と resources
をネストさせることで表現する。
生成される URL は以下の通り。
http://example.com/groups/1/users/2
などがリソースの URL になる。
Prefix Verb URI Pattern Controller#Action
group_users GET /groups/:group_id/users(.:format) users#index
POST /groups/:group_id/users(.:format) users#create
new_group_user GET /groups/:group_id/users/new(.:format) users#new
edit_group_user GET /groups/:group_id/users/:id/edit(.:format) users#edit
group_user GET /groups/:group_id/users/:id(.:format) users#show
PATCH /groups/:group_id/users/:id(.:format) users#update
PUT /groups/:group_id/users/:id(.:format) users#update
DELETE /groups/:group_id/users/:id(.:format) users#destroy
groups GET /groups(.:format) groups#index
POST /groups(.:format) groups#create
new_group GET /groups/new(.:format) groups#new
edit_group GET /groups/:id/edit(.:format) groups#edit
group GET /groups/:id(.:format) groups#show
PATCH /groups/:id(.:format) groups#update
PUT /groups/:id(.:format) groups#update
DELETE /groups/:id(.:format) groups#destroy
resource と resources
上では普通の resources
を用いて route を定義したが、resource
(単数形) というのもある。
Rails.application.routes.draw do
resource :book
end
この時の routes は以下の 6 action。
index
が無くなり、個々の URL から /:id
が消えた。
Prefix Verb URI Pattern Controller#Action
book POST /book(.:format) books#create
new_book GET /book/new(.:format) books#new
edit_book GET /book/edit(.:format) books#edit
GET /book(.:format) books#show
PATCH /book(.:format) books#update
PUT /book(.:format) books#update
DELETE /book(.:format) books#destroy
1 つしか存在しないので「一覧」が考えられない場合に使うんだが、
グローバルに 1 つの場合の他に、/users/:id/profile
のように
has_one
の関係になっているものに対しても使う。
resources :users do
resource :profile
end
こういうものはどう表現する?
csv ダウンロード
取得なので GET
です。
クライアントから、欲しいものをサーバに伝えるのに拡張子を使うのはまぁアリ。
GET http://example.com/books.csv
ページネート
取得なので GET
です。
「集合」というリソースを取得するときの条件なので、クエリパラメータで表現する。
GET http://example.com/books?page=2
検索
取得なので GET
です。
こちらも「集合」というリソースを取得するときの条件なので、クエリパラメータで表現する。
GET http://example.com/books?q=hoge
検索は頻出するので、分かりやすさ優先で
GET http://example.com/books/search?q=hoge
を許しても良いかもしれない。議論の余地があるところだと思う。
確認画面
URL として用意せずにクライアント側で処理するのが理想。
どうしてもやるなら draft
っていう状態を持たせることを考える。
確認画面問題とリソースモデリング - masakiのはてなダイアリー http://d.hatena.ne.jp/ikasam_a/20080305/1204733745
確認画面も頻出するので、分かりやすさ優先で
POST http://example.com/books/confirm
を許しても良いかもしれない。悩ましい。
公開フラグを立てる
確認画面に draft フラグを用意した時と同じ。
更新なので PATCH
です。
PATCH http://example.com/books/:id
draft=false
別解として、「公開」というリソースを POST
/ DELETE
することで
公開状態を変更するというのもアリ。
POST http://example.com/books/:id/publication
参考書
圧倒的にこの 2 冊。特に後者は web 系企業だとだいたい入社前に必読書として渡してると思う。
- RESTful Webサービス : Leonard Richardson, Sam Ruby, 山本 陽平, 株式会社クイープ : 本 : Amazon
- Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus) : 山本 陽平 : 本 : Amazon
前後リンク
- RESTful API のおさらい
- Rails での JSON API 実装まとめ
- スキーマファースト開発
- The NEXT of REST