「動けばいい」APIが負債になる理由
APIは一度公開すると、簡単には変更できません。クライアントがそのAPIに依存している以上、レスポンスの構造を変えたり、エンドポイントを廃止したりするたびに、すべての利用者に影響が波及します。だからこそ、「とりあえず動く」設計で作られたAPIは、サービスの成長とともに深刻な負債になります。
エンジニア歴3〜7年になると、自分でAPIを設計する機会が増えてきます。このフェーズで身につけておくべきなのは、実装の速さだけでなく「後から変えにくいものを最初に正しく作る」という設計の感覚です。この記事では、REST APIを前提に、実務で即使える設計の判断基準を体系的に整理します。
URIの設計——「名詞」で統一する原則
REST APIのURIは「リソース(名詞)」を表現し、「操作(動詞)」はHTTPメソッドで表現するのが基本原則です。この原則を守るだけで、URIの一貫性が大幅に向上します。
良い例と悪い例
| 悪い例(動詞が入っている) | 良い例(名詞ベース) |
|---|---|
GET /getUsers | GET /users |
POST /createOrder | POST /orders |
POST /deleteUser/123 | DELETE /users/123 |
GET /fetchUserOrders?id=123 | GET /users/123/orders |
URIは小文字・ハイフン区切りを使い(アンダースコアは避ける)、複数形を基本とするのが業界慣習です。/user よりも /users のほうがリソースの集合を表す意味として自然です。
階層構造は「親リソース/ID/子リソース」という形で表現します。/users/123/orders は「ユーザー123の注文一覧」を意味し、直感的に読み取れます。ただし階層が深くなりすぎると(3〜4階層以上)、URLの可読性が損なわれます。その場合はクエリパラメータで絞り込む設計が現実的です。
HTTPメソッドを正しく使い分ける
URIと並んでAPIの「文法」を構成するのがHTTPメソッドです。それぞれに明確な意味があり、正しく使い分けることでAPIの意図が伝わりやすくなります。
GETはリソースの取得に使います。副作用(データの変更)を持たない冪等な操作です。POSTはリソースの新規作成に使います。同じリクエストを複数回送ると、複数のリソースが作成される可能性があります(冪等ではない)。PUTはリソースの完全な置き換えに使います。指定したIDのリソース全体を上書きするイメージです。PATCHはリソースの部分更新に使います。変更したいフィールドだけを送るため、ペイロードが小さくなる利点があります。DELETEはリソースの削除に使います。
PUT と PATCH の使い分けは迷いやすいポイントです。たとえばユーザーのプロフィール更新で「名前だけ変える」なら PATCH、「プロフィール全体を丸ごと置き換える」なら PUT が適切です。多くの実装では PATCH を使う場面のほうが多くなります。
ステータスコードで意味を正確に伝える
HTTPステータスコードは、APIのレスポンスが「何を意味するのか」をクライアントに伝える重要な手段です。200 OK だけで全部返す実装は論外として、エラーの種類を正確にコードで表現することがAPIの品質に直結します。
| ステータスコード | 意味 | 使う場面の例 |
|---|---|---|
| 200 OK | 成功 | GETの正常レスポンス、PUTの更新成功 |
| 201 Created | 作成成功 | POSTでリソース作成成功時 |
| 204 No Content | 成功(ボディなし) | DELETEの成功、更新後にボディ不要な場合 |
| 400 Bad Request | リクエスト不正 | バリデーションエラー、必須パラメータ欠損 |
| 401 Unauthorized | 認証失敗 | トークンがない・無効 |
| 403 Forbidden | 認可失敗 | 認証済みだが権限がない |
| 404 Not Found | リソース不存在 | 指定IDのリソースが見つからない |
| 409 Conflict | 競合 | 重複登録、楽観的ロックの失敗 |
| 422 Unprocessable Entity | 意味的なバリデーションエラー | 形式は正しいが業務ルール違反 |
| 500 Internal Server Error | サーバー側の予期しないエラー | バグ・インフラ障害 |
401 と 403 は混同されがちです。「ログインしていない」は 401、「ログインはしているが権限がない」は 403 です。この区別がクライアント側のエラーハンドリングの品質に影響します。
レスポンス設計——一貫したJSON構造を作る
エラーレスポンスと成功レスポンスの構造が案件やエンドポイントごとにバラバラなAPIは、クライアントのエラーハンドリングコードを複雑にします。プロジェクト全体で統一したレスポンス構造を定義しておくことが重要です。
成功レスポンスの例として、データと一緒にメタ情報(ページネーション情報など)を返す構造が有効です。
{
"data": [ ... ],
"meta": {
"total": 100,
"page": 1,
"per_page": 20
}
}
エラーレスポンスは、エラーコード・メッセージ・詳細情報を含む構造を統一して返すことで、クライアント開発者が対応しやすくなります。
{
"error": {
"code": "VALIDATION_ERROR",
"message": "入力内容に誤りがあります",
"details": [
{ "field": "email", "message": "メールアドレスの形式が正しくありません" }
]
}
}
message は人間が読むためのもの、code はプログラムが処理するためのものと役割を明確に分けることがポイントです。
バージョニング——変更を安全に行うための仕組み
APIは一度リリースすると変更が難しいと冒頭で述べましたが、その解決策がバージョニングです。URIにバージョンを含める方式(/v1/users、/v2/users)が最も広く使われており、可視性が高く実装もシンプルです。
バージョンアップが必要なタイミングは、後方互換性を保てない変更を加えるときです。たとえばレスポンスのフィールド名を変更する、必須パラメータを追加する、エンドポイントを廃止するといった変更が該当します。一方でフィールドを追加するだけなら後方互換性を保てるため、バージョンアップ不要なことが多いです。
バージョンを分けた場合、古いバージョンをいつまでサポートするかの「廃止ポリシー」を事前に定めておくことも重要です。「v1は6ヶ月後に廃止」というアナウンスを早めに行うことで、クライアント側の移行を計画的に進められます。
認証・認可の設計は最初から考える
APIのセキュリティ設計は後付けが最も難しい領域です。エンドポイントを誰でも呼べる状態で開発を進め、後でトークン認証を追加しようとすると、既存のクライアントへの影響が広範囲に及びます。
現代のREST APIでは Bearer トークンを使ったJWT認証(Authorization ヘッダーにトークンを含める)が標準的です。OAuthやOpenID Connectを使ったサードパーティ認証が必要かどうかも、要件段階で確認しておきましょう。
また、エンドポイントごとに「認証が必要か」「どのロールが呼べるか」を明示的に定義したドキュメントを設計段階で用意することで、実装の抜け漏れとセキュリティリスクを大幅に減らせます。設計書があれば、レビュー時にも「このエンドポイントは認証なしで大丈夫か?」という確認が自然にできます。
ドキュメントは設計の一部である
最後に強調したいのが、ドキュメントの重要性です。どれだけ良く設計されたAPIでも、ドキュメントがなければ使う側は困ります。OpenAPI(Swagger)形式でAPI仕様を記述しておくと、インタラクティブなドキュメント生成・モックサーバーの自動生成・テストコードの自動生成など、周辺エコシステムとの連携が広がります。
APIを設計・実装するエンジニアは「自分がAPIの利用者だったら何が知りたいか」という視点を常に持ち続けることが重要です。エンドポイントの説明、リクエスト・レスポンスのサンプル、エラーコードの一覧——これらが整っているAPIは、チームの生産性と外部への信頼性を同時に高めます。