REST APIの設計とは、「どんなURLに、どのHTTPメソッドでリクエストを送ると、どんな結果が返るか」を決めることです。URLには名詞(リソース)を使い、操作は GET・POST・PUT・PATCH・DELETE で表し、結果はステータスコードで伝えるのが基本です。

基本のルールはシンプルですが、実務では「エラーはどんな形で返すか」「一覧は何件ずつ返すか」「同じリクエストが2回届いたらどうするか」など、決めておかないと、画面側の実装やチーム内で迷う点がたくさんあります。この記事では、実際に動かした注文APIとcurlの実行結果を使って、それぞれの決め方を解説します。最後に、設計レビューで使えるチェックリストも紹介します。

REST API設計の早見表

項目 基本のルール 例
URL 名詞・複数形・小文字、単語はハイフンでつなぐ /v1/orders、/v1/order-items
1件の指定 IDをパスに入れる /v1/orders/123
取得 GET GET /v1/orders
作成 POST POST /v1/orders → 201 Created
全体の置き換え PUT PUT /v1/orders/123
一部の更新 PATCH PATCH /v1/orders/123
削除 DELETE DELETE /v1/orders/123 → 204 No Content
絞り込み・並べ替え クエリパラメータ ?status=paid&sort=-created_at
エラーの形式 RFC 9457(Problem Details) application/problem+json
バージョン URLに入れるのがわかりやすい /v1/...

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「REST APIの設計|URL・ステータスコード・エラー形式の決め方」

URLの付け方

名詞を使い、操作はHTTPメソッドで表す

避けたい書き方 おすすめの書き方
POST /createOrder POST /v1/orders
GET /getOrderList GET /v1/orders
POST /deleteOrder?id=123 DELETE /v1/orders/123
GET /v1/order/123 GET /v1/orders/123(コレクションは複数形)

関係は1〜2階層まで

GET /v1/customers/42/orders        # 顧客42の注文一覧(わかりやすい)
GET /v1/customers/42/orders/7/items/3/options   # 深すぎる

深くなりすぎる場合は、GET /v1/order-items/3 のように、そのリソース単独のURLを用意します。

「動詞」がどうしても必要な操作

「注文をキャンセルする」「パスワードを再設定する」のように、単純な作成・更新・削除に当てはまらない操作もあります。その場合は、次のどちらかでチーム内で統一します。

方法 例
状態の更新として表す PATCH /v1/orders/123 に {"status": "cancelled"}
操作をサブリソースとして表す POST /v1/orders/123/cancel

キャンセルに理由や返金の処理が伴う場合は、後者の方が意図が明確になります。

HTTPメソッドの使い分け

メソッド 用途 冪等性 成功時のステータス
GET 取得 あり 200 OK
POST 作成、または冪等でない操作 なし 201 Created(作成)、202 Accepted(受け付けのみ)
PUT 全体の置き換え あり 200 OK または 204 No Content
PATCH 一部の更新 保証されない 200 OK
DELETE 削除 あり 204 No Content

冪等性(べきとうせい)とは、「同じリクエストを何回送っても、結果が同じになる」性質です。PUTで「数量を3にする」は何回送っても3ですが、POSTで「注文を作る」を2回送ると、注文が2件できてしまいます。この違いは、後半の「Idempotency-Key」で対策を紹介します。

ステータスコードの使い分け

場面 ステータスコード
取得・更新に成功 200 OK
作成に成功 201 Created(Location ヘッダーに新しいURL)
受け付けたが、処理は後で行う 202 Accepted
成功したが、返す内容がない(削除など) 204 No Content
リクエストの形式が正しくない(JSONが壊れているなど) 400 Bad Request
認証されていない(ログインしていない) 401 Unauthorized
権限がない 403 Forbidden
リソースが存在しない 404 Not Found
状態が合わず処理できない(発送済みの注文を変更など) 409 Conflict
入力値の検証エラー 422 Unprocessable Content(400で統一する設計もある)
リクエストが多すぎる 429 Too Many Requests
サーバー側の不具合 500 Internal Server Error
一時的に利用できない 503 Service Unavailable

大切なのは、エラーなのに200を返さないことです。200 OK で {"result": "error"} を返す設計にすると、画面側やHTTPのライブラリ、監視の仕組みが「成功」と判断してしまい、エラーの処理が複雑になります。

エラーの形式はRFC 9457に揃える

エラーの形式は、APIごとにばらばらになりがちです。RFC 9457(Problem Details for HTTP APIs)という標準の形式に揃えると、画面側で共通の処理が書けます。

項目 意味
type エラーの種類を表すURI
title エラーの種類の短い説明
status HTTPステータスコード
detail この発生についての具体的な説明
instance このエラーが発生した場所(リクエストのURLなど)

必要に応じて、errors のような独自の項目を追加できます。入力の検証エラーでは、どの項目がなぜエラーなのかを返すと、画面側で項目の横にメッセージを表示できます。

実際に動かして確認する

ここからは、Pythonの標準ライブラリだけで作った小さな注文APIに、curlでリクエストを送った結果です。

作成する(201 Created)

curl -i -X POST http://127.0.0.1:8765/v1/orders \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 7c1e-01' \
  -d '{"item":"マウス","quantity":2}'
HTTP/1.0 201 Created
Location: /v1/orders/2
Content-Type: application/json

{"id": 2, "item": "マウス", "quantity": 2, "status": "pending"}

作成したリソースのURLを Location ヘッダーで返し、本文には作成された内容を返しています。

入力エラー(422)

curl -i -X POST http://127.0.0.1:8765/v1/orders \
  -H 'Content-Type: application/json' \
  -d '{"quantity":0}'
HTTP/1.0 422 Unprocessable Entity
Content-Type: application/problem+json

{"type": "https://api.example.com/problems/validation-error",
 "title": "Validation Error", "status": 422,
 "detail": "入力内容に誤りがあります",
 "errors": [{"field": "item", "message": "必須です"},
            {"field": "quantity", "message": "1以上の整数で指定してください"}]}

エラーを1つずつではなく、まとめて返すと、利用者は1回で全部を直せます。

状態が合わない(409 Conflict)

curl -X PATCH http://127.0.0.1:8765/v1/orders/2 \
  -H 'Content-Type: application/json' -d '{"status":"shipped"}'
curl -X PATCH http://127.0.0.1:8765/v1/orders/2 \
  -H 'Content-Type: application/json' -d '{"quantity":3}'
{"id": 2, "item": "マウス", "quantity": 2, "status": "shipped"}
{"type": "https://api.example.com/problems/conflict", "title": "Conflict",
 "status": 409, "detail": "発送済みの注文は変更できません"}

入力の形式は正しいが、リソースの今の状態では処理できないときは409を返します。

削除(204)と、もう一度削除(404)

curl -s -o /dev/null -w "%{http_code}\n" -X DELETE http://127.0.0.1:8765/v1/orders/1
curl -s -o /dev/null -w "%{http_code}\n" -X DELETE http://127.0.0.1:8765/v1/orders/1
204
404

DELETEは冪等(何回送ってもリソースが消えている状態は同じ)ですが、2回目のステータスコードは404になります。冪等性とは「サーバーの状態が同じになる」ことで、返ってくるステータスコードまで同じとは限りません。

ページング:オフセット方式とカーソル方式

一覧を返すAPIでは、一度に返す件数を制限します。制限がないと、データが増えたときに応答が遅くなり、サーバーの負荷も高くなります。

方式 リクエストの例 長所 短所
オフセット方式 ?limit=20&offset=40 実装が簡単。「5ページ目」に直接移動できる データが多いと遅くなる。途中で追加・削除があると、重複や抜けが出る
カーソル方式 ?limit=20&cursor=eyJpZCI6MTAwfQ 大量のデータでも速い。途中の追加・削除に強い 任意のページに直接移動できない
{
  "data": [ { "id": 101, "item": "キーボード" }, "..." ],
  "next_cursor": "eyJpZCI6MTIwfQ"
}

管理画面のようにページ番号で移動する画面ではオフセット方式、無限スクロールや、外部連携で全件を取得する場面ではカーソル方式が向いています。どちらの場合も、limit には上限(100件など)を設けます。

絞り込み・並べ替え・項目の選択

目的 例
絞り込み GET /v1/orders?status=paid&customer_id=42
期間 GET /v1/orders?created_from=2026-09-01&created_to=2026-09-30
並べ替え GET /v1/orders?sort=-created_at(- で降順)
返す項目を選ぶ GET /v1/orders?fields=id,status,total

パラメータの名前の付け方(created_from か from か、sort=-created_at か order=desc か)は、API全体で統一します。

バージョン管理

方法 例 特徴
URL /v1/orders わかりやすく、ブラウザやログでも確認しやすい。最も一般的
クエリパラメータ /orders?version=1 URLは変わらないが、キャッシュの扱いに注意
ヘッダー Accept: application/vnd.example.v1+json URLがきれいだが、確認や試験がしにくい

項目の追加のような、既存の利用者に影響しない変更では、バージョンを上げる必要はありません。項目の削除・名前の変更・型の変更のように、既存の利用者が動かなくなる変更をするときに、新しいバージョンを用意します。

冪等性とIdempotency-Key

通信が途中で切れた場合、利用者は「注文が作られたかどうか」がわかりません。POSTを再送すると、注文が二重にできるおそれがあります。

そこで、リクエストごとに一意のキー(Idempotency-Key)をヘッダーに付けて送り、サーバー側で同じキーのリクエストは1回だけ処理する方法があります。決済のAPIなどで広く使われている方法です。

先ほどの例で、同じキーのリクエストをもう一度送った結果です。

curl -X POST http://127.0.0.1:8765/v1/orders \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 7c1e-01' \
  -d '{"item":"マウス","quantity":2}'
{"id": 2, "item": "マウス", "quantity": 2, "status": "pending"}

新しい注文は作られず、1回目と同じ注文(id: 2)が返りました。再送しても安全なため、利用者は通信エラーのときに安心して再試行できます。実際の運用では、キーを一定期間(24時間など)保存し、同じキーで内容が違うリクエストが来た場合はエラーにします。

認証の渡し方

方法 例 用途
Bearerトークン Authorization: Bearer eyJhbGci... ログインした利用者の操作(OAuth・JWTなど)
APIキー X-API-Key: sk_live_... システム同士の連携
  • 認証の情報をURLに入れない(?token=... はアクセスログやブラウザの履歴に残る)
  • 必ずHTTPSを使う
  • 認証されていなければ401、権限がなければ403を返す

設計レビューのチェックリスト

観点 チェック項目
URL 名詞・複数形になっているか。動詞が入っていないか
URL 階層が深すぎないか(2階層程度まで)
メソッド 取得はGET、作成はPOST、更新はPUT・PATCH、削除はDELETEになっているか
ステータス エラーなのに200を返していないか
ステータス 作成は201と Location、削除は204になっているか
エラー 形式がAPI全体で統一されているか(RFC 9457など)
エラー 入力エラーで、どの項目がなぜエラーなのかがわかるか
エラー 内部の情報(SQL文、スタックトレース)を返していないか
一覧 ページングがあり、limit に上限があるか
命名 項目名の書き方(created_at か createdAt か)が統一されているか
日時 ISO 8601形式(2026-09-28T10:00:00+09:00)で、タイムゾーンが明確か
冪等性 二重に実行されると困るPOSTで、Idempotency-Keyなどの対策があるか
認証 認証の情報をURLに入れていないか。401と403を使い分けているか
互換性 既存の利用者が動かなくなる変更がないか。ある場合はバージョンを上げたか
文書 OpenAPIなどで仕様が文書化されているか

よくある質問

Q. PUTとPATCHはどう使い分ければいいですか? A. PUTはリソース全体を送って置き換える、PATCHは変更したい項目だけを送る操作です。画面の一部の項目だけを更新することが多い場合は、PATCHの方が使いやすくなります。

Q. 項目名はスネークケースとキャメルケースのどちらがいいですか? A. どちらでも構いませんが、API全体で統一することが大切です。JavaScriptの画面から使うことが多いならキャメルケース、PythonやRubyのサーバーならスネークケースを選ぶことが多いです。

Q. RESTとGraphQLはどちらを選べばいいですか? A. 画面ごとに必要な項目が大きく異なり、1回のリクエストで複数のリソースをまとめて取得したい場合はGraphQLが向いています。外部に公開するAPIや、シンプルな業務システムでは、HTTPの仕組み(キャッシュ・ステータスコード)をそのまま活かせるRESTの方が扱いやすいことが多いです。

Q. エラーメッセージは日本語でもいいですか? A. 画面にそのまま表示するメッセージであれば、利用者の言語で問題ありません。プログラムで判定するための type や、項目名などは英語の固定値にしておくと、表示の言語を変えても処理に影響しません。

まとめ

  • URLは名詞・複数形、操作はHTTPメソッドで表す
  • ステータスコードで結果を伝え、エラーなのに200を返さない
  • エラーは RFC 9457 の形式に揃え、入力エラーは項目ごとにまとめて返す
  • 一覧はページングし、limit に上限を設ける。大量のデータにはカーソル方式
  • 既存の利用者が動かなくなる変更をするときに、バージョンを上げる
  • 二重に実行されると困るPOSTには、Idempotency-Keyで再送に備える
  • 設計はチェックリストでレビューし、OpenAPIで文書化する

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「REST APIの設計|URL・ステータスコード・エラー形式の決め方」

株式会社RJCでは、使う人にとってわかりやすいAPIを、チームで議論しながら設計しています。こうした知識を仲間と共有しながら、一緒に成長を楽しんでいます。

株式会社RJC ― SI事業・SES事業・AI駆動開発。未経験からエンジニアに育てるのが得意な会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?