REST APIはWeb APIで最も利用されるAPI設計のうちの 1 つです。
この記事では、REST APIを設計する際の方針や命名などについての概要をまとめます。
基本方針
以下はリソース URL (↔︎ 非リソース URL )・ HTTP メソッドについての基本的な設計方針です。
| 処理の内容 | HTTPメソッド | URL | プログラムメソッド |
|---|---|---|---|
| リソースデータを全て取得する | GET | ~/resources |
ListResources |
| idと一致するリソースを一件取得する | GET | ~/resources/{id} |
GetResource |
| リソースを一件登録する | POST | ~/resources |
CreateResource |
| idと一致するリソースを一件更新する | PUT | ~/resources/{id} |
UpdateResource |
| idと一致するリソースを一件更新する(ただし提供されたフィールドのみ) | PATCH | ~/resources/{id} |
UpdateResource |
| idと一致するリソースを一件削除する | DELETE | ~/resources/{id} |
DeleteResource |
| リソースの利用可能なメソッドとパラメータを返す | OPTIONS | ~/resources |
- |
命名規則
命名は 統一することが大切 で、正しいものが 1 つに定まるとは限りません。
プログラミング言語・ライブラリなどにより流儀がありますので、以下は一例として捉えてください。
- URL は ケバブケース
- NG :
/systemOrders、/system_orders - OK :
/system-orders
- NG :
- URL中の
resourcesはリソースのコレクションを表し、 複数形の名詞 で表現- NG :
GET /user、GET /User - OK :
GET /users
- NG :
- URL中のパスパラメータ・リソース ID部分は キャメルケース
- NG :
/system-orders/{order_id}、/system-orders/{OrderId} - OK :
/system-orders/{orderId} - ※ケバブケース(
{order-id})への統一でも大丈夫です
- NG :
- URL はコレクションで始まり、識別子で終わる
- NG :
GET /shops/{shopId}/category/{categoryId}/price - OK :
GET /shops/{shopId}/、GET /category/{categoryId}
- NG :
- リソース URL に動詞を使わない
- NG :
POST /updateuser/{userId}、GET /getusers - OK :
PUT /user/{userId}
- NG :
- 非リソース URL は動詞を使う
- OK :
POST /alerts/245743/resend - リソースへの CRUD ではなく、特定のビジネスロジックを実行する場合です
- OK :
- クエリパラメータは スネークケース
- OK :
customer_number、order_id、billing_address
- OK :
- JSON のプロパティは キャメルケース
- OK :
customerNumber、orderId、billingAddress - ※スネークケース(
customer_number)への統一でも大丈夫です
- OK :
- 各 API エンドポイントに
/health、/version、/metricsを実装する/health: ヘルスチェック/version: バージョン番号/metrics: 平均応答時間などのさまざまな metrics を提供/debugと/statusもおすすめです
- リソース名にテーブル名を使わない
- NG :
product_order - OK :
product-orders
- NG :
- レスポンスにリソースの総数を含める
{
users: [
...
],
total: 34 # これ
}
ゴールデンルール
API 設計で迷ったときは、以下のルールを参考にしてください。
- フラットはネストより良い
- 単純は複雑より良い
- 文字列は数字より良い
- 一貫性はカスタマイズより良い
クエリパラメータの使用
クエリパラメータを利用すると URL の複雑性が下がり、 API の柔軟性が上がります。
以下を参考にクエリパラメータを含めた API 設計を行なってください。
- 検索条件を指定したい場合 -> SELECT 文の WHERE 句のように使用する
- 例)
~/dogs?age=3-> 3 歳の犬だけを取得する
- 例)
- ある1つのリソースの一部の項目だけを取得したい場合(Partial response) -> 「 fields 」にカンマ区切りで指定
- 例)
~/dogs/1234?field=name,color,location
- 例)
- あるリソースから件数を指定して取得したい場合(Pagination) -> 「 limit 」と「 offset 」で指定する
- 「offset」番目から「limit」件取得する
- 例)
~/dogs?offset=25&limit=50 - 全レコード件数を「metadata」としてレスポンスに含める
リソース操作
計算・翻訳・変換など、リソースへの CRUD 以外の操作も存在します。
その場合は名詞ではな 動詞 を使用しましょう。
- 例)
~/convert?from=EUR&to=CNY&amount=100
この API はリソース URL の設計からはやや外れることになりますので、その特殊性について認識できるよう明記するようにしましょう。
また、この API で取得できるデータはデータベースの値を直接返すのではなく、ロジックで計算して得た結果であるということもまた認識できるよう明記しましょう。
コンテンツネゴシエーション
Restful API においてクライアントからサーバへレスポンスのフォーマットを要求することを コンテンツネゴシエーション といいます。
クライアントからサーバへコンテンツのフォーマットを要求する方法として以下のようなものがあります。
- URLの拡張子による指定
- 例)HTML形式の要求:
https://myserver/myapp/accounts/list.html - 例)spreadsheet形式の要求:
https://myserver/myapp/accounts/list.xls
- 例)HTML形式の要求:
- リクエスト(クエリ)パラメータによる指定
- 例)spreadsheet形式の要求
https://myserver/myapp/accounts/list?format=xlshttps://myserver/myapp/accounts/list?mediaType=xls
- 例)spreadsheet形式の要求
- Acceptヘッダによる指定
- 例)JSON形式の要求:
Accept: application/json
- 例)JSON形式の要求:
個人的には Accept ヘッダ による指定を推奨します。
「Accept-Language」「Accept-Encoding」も併せて利用するとよいでしょう。
API 設計のステップ
API 設計の大まかな流れについてご紹介します。
- 対象となるデータを洗い出します
- ER 図等を記載します
- 洗い出したデータをリソースに分割します
- ER 図の 1 エンティティを 1 リソースにしたり、結合したテーブルを 1 リソースにしたりします
- リソースに URL を割りあてます
- 先述の命名規則に従いましょう
- URL が右に行くほど自然な階層構造・サブセットになっているか確認しましょう
- 例)オーナー 5678 が飼っている犬を表す場合
~/owners/5678/dogs~/resources/{id}/resources/{id}以上に階層を深くしないようにしましょう- これ以上複雑にしたい場合はクエリパラメータの使用などを検討してください
- リソースに対してインターフェースを割り当てます
- HTTPメソッド(GET、POST、PUT、DELETE等)の選択
- クライアントから受信するメディアタイプを 1 つ以上決めます
application/json、application/xml、等
- クライアントへ返信するメディアタイプを 1 つ以上決めます
application/json、application/xml、等
- 接続性(Connectedness)を高めます
- リソースはハイパーメディアリンクによって他のリソースと接続することができます
- クライアントは自ら URL を組み立てることは行わず、サーバから送られてくるハイパーメディアリンクを利用することができます
- 正常系を考えます(適切なリクエストがあったとき)
- ステータスコードを選択します
- 例外条件を考えます(不適切なリクエストがあったとき)
- ステータスコードを選択します
- ステータスコードと例外をマッピングします
レスポンス内容
ステータスコードやボディは概ね下記のものを検討すればよいでしょう。
GET
| HTTP Status Code | 意味 | ボディ | その他 |
|---|---|---|---|
| 200 OK | 正常に処理が完了 | 取得対象データ | |
| 204 No Content | コレクションは存在するが、対象IDのリソースが存在しない | 空 |
POST
| HTTP Status Code | 意味 | ボディ | その他 |
|---|---|---|---|
| 200 OK | 新しいリソース作成以外の処理が正常に完了 | 処理結果データ | |
| 201 Created | 正常に処理が完了 | 新規作成リソースデータ | Locationヘッダに作成したリソース URI |
| 204 No Content | コレクションは存在するが、対象IDのリソースが存在しない | 空 | |
| 400 Bad Request | クライアントから無効なリソース登録要求 | エラー内容そのものや URI |
PUT/PATCH
| HTTP Status Code | 意味 | ボディ | その他 |
|---|---|---|---|
| 200 OK or 204 No Content | リソースの更新処理が正常に完了 | 処理結果データ | |
| 201 Created | 正常に処理が完了 | 新規作成リソースデータ | Locationヘッダに作成したリソース URI |
| 400 Bad Request | クライアントから無効なリソース登録要求 | エラー内容そのものや URI | |
| 409 Conflict | リソースの現状の状態の矛盾している | 更新順序の前後等により発生 |
DELETE
| HTTP Status Code | 意味 | ボディ | その他 |
|---|---|---|---|
| 204 No Content | 正常に処理が完了 | 空 |
共通
| HTTP Status Code | 意味 | 補足 |
|---|---|---|
| 301 MovedPermanently | アクセスしたリソースが別のURIに恒久的に移動した | Locationヘッダに移動先のURIを付与する |
| 303 See Other | 別のURIにアクセスしてほしい | Locationヘッダに移動先の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の表し方
その URL が API であることを表す方法には以下のようなものがあります。
- サブドメインを置く
- 例)
https://api.example.com/
- 例)
- パスに置く
- 例)
https://example.com/api/
- 例)
- 表現しない
どのパターンも見るので、どれが良いとかは断言しづらいです。
開発するサービス特性により選択してください。
API をパスで表現していて、且つ、同じドメインでWebページを公開しているサービスの場合、 https://example.com/web/ のようにするサービスも見かけます。
API バージョンの表し方
API の仕様が変更して後方互換性の維持が難しくなる場合を想定して、 URL や HTTP ヘッダに API バージョン情報を付与する方法があります。
- URL にバージョン情報を付与する
- 例)
http://example.com/api/2/:バージョン番号(整数)のみの付与 - 例)
http://example.com/api/2.0/:バージョン番号(少数)のみの付与 - 例)
http://example.com/api/v2/:「v」をつける(整数)
- 例)
- クエリパラメータにバージョン情報を付与する
- 例)
~/resources?v=2
- 例)
- HTTP ヘッダに付与する( メディアタイプバージョニング )
Content-Typeヘッダにapplication/vnd.github.v3+jsonのようにバージョン情報を付与してレスポンスする- クライアントは
Acceptヘッダにapplication/vnd.github.v3+jsonのようにバージョン情報を付与してリクエストする
- バージョン情報を付与しない
- 異なる API を新規に作成する
これまた正解は無い(分からない)ので、サービス特性などにより選択してください。
その他、決める際に困りそうなネタ
ほぼメモです。スルーしてください。
- リソースの移動、コピー
- 複数レコードを選択して更新する API
- 207 Multi-Statusで返したくなる、、、
Web画面の基本方針
某フレームワークのスキャフォルドっぽいですが、 Web 画面の URL 設計方針についてもメモしておきます。
| 処理の内容 | 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 |
参考
- RESTful Web API の設計
- Cloud APIs API 設計ガイド
- Zalando RESTful API と イベントスキーマのガイドライン
- Original: Zalando RESTful API and Event Guidelines
