この記事で学べること
- RESTful APIの基本概念と原則
- APIのURLやエンドポイントの正しい設計方法
- HTTPメソッド(GET/POST/PUT/PATCH/DELETE)の適切な使い分け
- ステータスコードの重要性と主要なコードの意味
- REST API設計における12のベストプラクティス
はじめに
これまでAPI設計(主にWEB API)をしたことがありますが、原則のようなものを勉強したことがなかったので、REST APIの設計方法についてググって調べた情報をまとめました。
RESTful APIの身近な例
私たちが日常的に使うサービスの多くはRESTful APIで構築されています。
例えば以下のようなものがあります。
- SNSアプリ:投稿の取得、いいねの追加、コメントの投稿など全てAPIで通信
- 天気予報アプリ:気象データをAPI経由で取得
- オンラインショッピング:商品検索、カートへの追加、注文処理などをAPIで実行
- 音楽ストリーミング:曲の検索、再生、プレイリストの作成などをAPIで制御
- 地図アプリ:位置情報の取得、経路探索などをAPIで処理
これらのサービスはフロントエンド(見た目)とバックエンド(データ処理)が分離されており、その間の通信をRESTful APIが担っています。
APIの種類
ちなみに、APIの種類には今回取り上げるREST API以外にも色々な種類があります。
- SOAP:XMLベースの古くからある通信プロトコル(詳細)
- GraphQL:必要なデータだけを一度のリクエストで取得できる柔軟なクエリ言語(詳細)
- gRPC:Googleが開発した高速なRPC(遠隔手続き呼び出し)フレームワーク(詳細)
- WebSocket:双方向通信を可能にするプロトコル
それぞれのAPIについてはリンク先のQiita記事で詳しく解説されていますので、ご興味があればそちらもご覧ください。
記事の構成
- RESTful APIとは?
- REST APIの基本的な考え方
- URLの設計方法
- HTTPメソッドの使い分け
- ステータスコードの重要性
- 12のベストプラクティス
- 参考文献
RESTful APIとは?
RESTful APIとはREST
の設計原則に基づいたAPIのことです。
*REST:「REpresentational State Transfer」
RESTには6つの設計原則があります。
- クライアント・サーバー分離:ユーザーインターフェースとデータ処理を分離
- ステートレス:リクエストは独立しており、サーバーはセッション情報を保持しない
- キャッシュ可能:レスポンスはキャッシュ可能か否かを明示する
- 統一インターフェース:シンプルで一貫性のあるインターフェース設計
- 階層化システム:クライアントはサーバーの複雑さを知る必要がない
- コードオンデマンド(任意):クライアントの機能を拡張できる
分かりやすく言うと、RESTful APIはインターネットを介して異なるシステム同士が安全に情報をやり取りするための「共通言語」のようなものです。
例えば、天気予報アプリが気象データサービスから情報を取得したり、ショッピングサイトが決済システムと連携したりする際に使われています。
日常生活の例えで言うと、レストランでの注文のようなものです。
- メニュー(API仕様)があり、何が注文できるかが明確
- 注文する(リクエストを送る)と、料理(データ)が提供される
- 特定の言葉や作法(HTTPメソッド)を使って伝える
簡単に言えば、以下のような特徴を持つAPIです。
- Webのようなリソース(データや情報)中心の考え方
- HTTPメソッドを使って、リソースに対する操作を表現
- ステートレス(状態を持たない)な通信
- 統一されたインターフェース
例えば、X(旧Twitter)のAPIで考えると
- ツイートはリソース
- 新しいツイートの投稿はPOSTメソッド
- ツイートの取得はGETメソッド
- ツイートの削除はDELETEメソッド
という形で表現されます。
ChatGPTに聞いてみたところ
「REST APIは、Webサービス同士がお互いに会話するための共通ルールみたいなものだよ。例えば、あるサイトのデータを別のアプリで使いたいとき、REST APIを使えば決まった方法でデータをやり取りできる。特に、HTTPという既存の仕組みを活用している点がポイント!」
なるほど、要するにアプリケーション間でデータをやり取りするための標準的な方法
ということなんですね。ふむふむ。フレンドリー。
REST APIの基本的な考え方
RESTには以下のような基本的な考え方があることがわかりました。
- リソース中心:データや機能を「リソース」として考える(例:ユーザー、投稿、コメントなど)
- HTTPメソッドでの操作:同じURLでも、GETやPOSTなど操作の種類で動作が変わる
- ステートレス:サーバーはリクエスト間で状態を保持しない(毎回必要な情報をすべて送る)
ネットショッピングを例に出します。
- 商品(リソース)には固有の商品ID(URL)がある
- 商品情報を見る(GET)、カートに商品を追加する(POST)、配送先住所を変更する(PUT)、カートから商品を削除する(DELETE)
- 毎回ログイン情報を送る(認証情報を送る)
例えば、ECサイトのAPIではこのようになります。
GET /products/123 # 商品ID:123の情報を取得
POST /cart/items # カートに商品を追加
PUT /user/address # 配送先住所を更新
DELETE /cart/items/123 # カートから商品ID:123を削除
URLの設計:最初にハマったところ
当時、設計の作業を始めてやった時にレビューで指摘を食らった内容です。
最初に自分でAPI設計をしようとしたとき、こんなURLを考えていました。
/getUsers
/createUser
/updateUserPassword
/deleteUser
しかし、これはREST的には間違いだと知りました。
RESTではURLはリソースを表し、操作はHTTPメソッドで表現するのが正しいアプローチです。
GET /users # ユーザー一覧を取得
POST /users # 新しいユーザーを作成
PUT /users/{id} # 特定ユーザーを更新
DELETE /users/{id} # 特定ユーザーを削除
HTTPメソッドの使い分け:混乱しやすいポイント
HTTPメソッドを分かりやすい表現でまとめました。
- GET:データを読み取るだけ(副作用なし)
- POST:新しいリソースを作成する
- PUT:リソース全体を置き換える(すべてのフィールドを送る必要あり)
- PATCH:リソースの一部を更新する(変更したいフィールドだけ送れば良い)
- DELETE:リソースを削除する
メソッド | 主な用途 | 特徴 |
---|---|---|
GET | 取得 | 安全、キャッシュ可能 |
POST | 作成 | リクエスト毎に異なる結果 |
PUT | 完全更新 | 同じリクエストで同じ結果 |
PATCH | 部分更新 | 更新箇所のみ指定可能 |
DELETE | 削除 | 同じリクエストで同じ結果 |
PUTとPATCHの違いは、PUTが「完全な置き換え」でPATCHが「部分更新」という点です。
例えば、ユーザープロフィールを更新する場合
# PUTの場合:すべてのフィールドを送る必要あり
PUT /users/123
{
"name": "山田太郎",
"email": "yamada@example.com",
"age": 25,
"address": "東京都渋谷区"
}
# PATCHの場合:変更したいフィールドだけでOK
PATCH /users/123
{
"address": "東京都新宿区"
}
ステータスコード:意外と重要
API開発で意外と重要だったのが、適切なHTTPステータスコードの使用です。
最初は「200」と「400」、「404」しか使っていませんでしたが、適切なステータスコードを返すことでクライアント側の実装がとても楽になります。
よく使うステータスコード
- 200 OK:リクエスト成功
- 201 Created:リソース作成成功
- 204 No Content:成功したが返すコンテンツなし(DELETEの成功など)
- 400 Bad Request:リクエスト形式の誤り
- 401 Unauthorized:認証が必要
- 403 Forbidden:権限がない
- 404 Not Found:リソースが見つからない
- 500 Internal Server Error:サーバー内部エラー
ベストプラクティス
1. 一貫した命名規則を使う
- 複数形のリソース名を使う(
/user
ではなく/users
) - ケバブケース(
user-profiles
)またはスネークケース(user_profiles
)を使う - 動詞ではなく名詞でリソースを表現する
2. ネストしたリソースを適切に表現する
- 例:
/users/{id}/posts
(特定ユーザーの投稿一覧) - ネストは最大2〜3階層までにとどめる
3. クエリパラメータを効果的に使う
- フィルタリング:
/users?status=active
- ソート:
/users?sort=name&order=desc
- ページネーション:
/users?page=2&limit=10
- 検索:
/users?search=山田
4. 適切なHTTPメソッドとステータスコードを使う
- POST成功時は201、DELETEは204など状況に応じたステータスコードを返す
- 安全なメソッド(GETなど)と安全でないメソッドを区別する
5. バージョニングを導入する
- URLベース:
/api/v1/users
- 後方互換性の有無
6. 適切なエラーレスポンスを返す
- エラーコード、メッセージ、詳細情報を含める
- 開発者が問題を特定しやすい情報を提供する
{
"error": "ValidationError",
"message": "ユーザー名は必須です",
"status": 400,
"timestamp": "2025-12-31 12:34:56"
}
7. 部分更新にはPATCHを使用する
- 全体更新(PUT)と部分更新(PATCH)を適切に使い分ける
8. コンテンツネゴシエーションを実装する
-
Accept
ヘッダーを使ってJSON/XMLなど複数のフォーマットに対応する -
Content-Type
ヘッダーで送信データの形式を明示する
参考 https://developer.mozilla.org/ja/docs/Web/HTTP/Guides/Content_negotiation
9. レート制限を設ける
- APIの過剰利用を防ぐために制限を設定
- ヘッダーで制限情報を伝える(
X-RateLimit-Limit
など)
10. キャッシュ
-
Last-Modified
などヘッダーを設定(参考) -
Cache-Control
ヘッダーでキャッシュ方針を指定
参考 https://developer.mozilla.org/ja/docs/Web/HTTP/Reference/Headers/Cache-Control
11. CORS(Cross-Origin Resource Sharing)を適切に設定する
- 必要なオリジンからのアクセスのみを許可
- プリフライトリクエストを正しく処理する
12. セキュリティのベストプラクティスを遵守する
- 常にHTTPSを使用する、など
- 適切な認証・認可の仕組みを実装する