読者です 読者をやめる 読者になる 読者になる

ぺーぺーSEのブログ

備忘録・メモ用サイト。

Restful設計まとめ

Restfulな設計を個人的にまとめる。
あくまで個人的なまとめで個人的にどこからでも参照できるようにここに張る。
正しいとか間違ってるとかどうでもいいし、参考にするしないは個人で判断して。


基本方針

Restful APIの設計は基本的に以下。

処理の内容 HTTPメソッド URL
リソースデータを全て取得する GET ~/api/resources
idと一致するリソースを一件取得する GET ~/api/resources/{id}
idと一致するリソースを一件更新する PUT ~/api/resources/{id}
リソースを一件登録する POST ~/api/resources
idと一致するリソースを一件削除する DELETE ~/api/resources/{id}
リソースの利用可能なメソッドとパラメータを返す OPTIONS ~/api/resources

URL中の「resources」はリソースを表し、名詞の複数にする。
(例)users、customers、等


コンテンツネゴシエーション

Restful APIにおいてクライアントからサーバへレスポンスのフォーマットを要求することをコンテンツネゴシエーションという。
クライアントからサーバへコンテンツのフォーマットを要求する方法として以下の3つがある。

  1. URLの拡張子
  2. リクエスト(クエリ)パラメータ
  3. Acceptヘッダ
    • 例)JSON形式の要求
      • Accept: application/json

個人的には「Acceptヘッダ」推奨。
「Accept-Language」「Accept-Encoding」もあるから使えばいいじゃん。


設計ステップ
  1. 対象となるデータを洗い出す
    • ER図とか書くんじゃね
  2. 洗い出したデータをリソースに分割する
    • ER図の1エンティティを1リソースにしたり、結合したテーブルを1リソースにしたり
  3. リソースにURLを割りあてる
    • リソースは名詞の複数にすること
      • 例外的に動詞を使用する場合がある(後述)
    • URLが右に行くほど自然な階層構造・サブセットになっているか
    • 例)オーナー5678が飼っている犬を表す場合
      • ~/api/owners/5678/dogs
      • 「~/api/resources/identifier/resources/idendifier」以上に階層を深くしない
      • これ以上複雑にしたい場合はクエリパラメータを使用する
  4. リソースに対してインターフェースを割り当てる
    • HTTPメソッド(GET、POST、PUT、DELETE等)の選択
  5. クライアントから受信するメディアタイプを1つ以上決める
    • application/json、application/xml、等
  6. クライアントへ返信するメディアタイプを1つ以上決める
    • application/json、application/xml、等
  7. 接続性(Connectedness)を高める
    • リソースはハイパーメディアリンクによって他のリソースと接続することができる
    • クライアントは自らURLを組み立てることは行わず、サーバから送られてくるハイパーメディアリンクを利用する
  8. 正常系を考える(適切なリクエストがあったとき何が起こるか
  9. 例外条件を考える(不適切なリクエストがあったとき何が起こるか

ステータスコードは概ね下記のものを検討すればよい。

HTTP Status Code 意味 発生し得る契機
200 OK 正常に処理が完了 GET、PUT、DELETEの結果
201 Created 新規リソースが作成された POSTの結果
204 No Content 正常に完了したが、特に返却するBodyが無い POST、DELETEの結果
301 MovedPermanently アクセスしたリソースが別のURIに恒久的に移動した リソースのURIが変わった時
Locationヘッダに移動先のURIを付与する
303 See Other 別のURIにアクセスしてほしい アクセスURIを変えてほしい
304 Not Modified リソースの変更をしなかった POST、PUT、DELETEの結果
307 Temporary Redirect 一時的なリダイレクト 閉塞時等
Locationヘッダにリダイレクト先のURIを付与する
400 Bad Request クライアントからのHTTPリクエストに誤りがありサーバで処理できない
401 Unauthorized クライアントが認証されていない
403 Forbidden クライアントの権限不足
404 Not Found アクセスしたURIが存在しない
406 Not Acceptable リクエストのAcceptヘッダがサーバで受け入れられない コンテンツネゴシエーション失敗
415 Unsupported MediaTYpe リクエストのContent-Typeヘッダがサーバで受け入れられない サーバ側でBodyを解釈できない
409 Conflict リソースの現状の状態の矛盾している 更新順序の前後等
500 Internal Server Error サーバ内でエラーが発生した 上記以外のサーバエラー

上記は若干やり過ぎ感があるかも。。。


レスポンスの設計
API処理の結果 レスポンスStatus Code レスポンスBody
リソースの取得に成功 200 OK 取得対象データ
リソースの登録に成功 201 Created 追加したデータ(Locationヘッダには追加したデータのURL)
リソースの更新・削除に成功 200 OK
リソースが存在しない 404 Not Found
リクエストに検証エラー 400 Bad Request エラー情報
サーバ側でエラー 500 Internal Server Error エラー情報

あくまで例だよ。


APIの表し方

そのURLがAPIであることを表す方法は大きく2つある。

  1. サブドメインを置く
  2. パスに置く

参考によるとサブドメインが多数派らしい。
このまとめの最初の方ではパスで表現している。
ちなみにAPIをパスで表現していて、且つ、同じドメインでWebページを公開しているサービスの場合、「http://example.com/web/」のようにするサービスがある模様。


バージョンの表し方

APIが仕様変更した際に既存クライアントに影響を与えないようにURLにバージョンを指定するサービスが多い。
その際、以下の観点がある。

トレンドはシンプルさを求めた「v無し」「整数」のようだ。


拡張

基本方針だけでは不十分な場合に拡張するときの考え方。


クエリパラメータの使用
  • 検索条件を指定したい場合
    • SELECT文のWHERE句のように使用する
    • 例)~/api/dogs?age=3
      • 3歳の犬だけを取得する
  • ある1つのリソースの一部の項目だけを取得したい場合(Partial response)
    • 「fields」にカンマ区切りで指定
    • 例)~/api/dogs/1234?field=name,color,location
  • あるリソースから件数を指定して取得したい場合(Pagination)
    • 「limit」と「offset」で指定する
    • 「offset」番目から「limit」件取得する
    • 例)~/api/dogs?offset=25&limit=50
    • 全レコード件数を「metadata」としてレスポンスに含める


リソース操作

計算・翻訳・変換など、リソースへのCRUD以外の操作も存在し得る。
その場合は名詞ではなく動詞を使用する。
(例)~/api/convert?from=EUR&to=CNY&amount=100
このAPIはあくまで特殊なケースであることを明記・認識する必要がある。
また、このAPIで取得できるデータはデータベースの値を直接返すのではなく、ロジックで計算して得た結果であるということもまた明記・認識する必要がある。


URLの配布

jsはURLを文字列結合で作るのではなく「URI-Templates」を渡すのがよい。
http://tools.ietf.org/html/rfc6570

その他、決める際に困りそうなこと

答えは出てないがメモっとく。

  • リソースの移動、コピー
  • 複数レコードをせんたくして更新するIF
    • 207 Multi-Statusで返したくなっちゃう
Web画面の基本方針
処理の内容 HTTPメソッド URL
一覧画面表示 GET ~/web/resources
詳細画面表示 GET ~/web/resources/{id}
追加Form表示 GET ~/web/resources/new
追加アクション POST ~/web/resources/new
編集フォーム表示 GET ~/web/resources/{id}/edit
編集アクション POST ~/web/resources/{id}/edit
削除画面表示 GET ~/web/resources/{id}/delete
削除アクション POST ~/web/resources/{id}/delete

Railsっぽい。


参考:
http://developer.mixi.co.jp/appli/spec/pc/restful-api-for-pc/restful-api-details/
http://www.atmarkit.co.jp/ait/spv/1310/23/news078_2.html
http://qiita.com/irxground/items/cd83786b10d81eecce77
http://www.slideshare.net/mobile/t_wada/restful-web-design-review
http://d.hatena.ne.jp/cou929_la/touch/20130121/1358776754
http://blog.katty.in/2992