RESTの6つの制約
RESTは「表現状態転送(Representational State Transfer)」の略で、Webの分散システムを設計するためのアーキテクチャスタイルだ。以下の6つの制約で定義される。
| 制約 | 説明 | 実務での意味 |
|---|---|---|
| クライアント・サーバー | 関心の分離 | フロントとバックを独立に開発可能 |
| ステートレス | サーバーにセッション状態を持たない | リクエストごとに認証情報を送信 |
| キャッシュ可能 | レスポンスにキャッシュ制御を含める | Cache-Control, ETagの活用 |
| 統一インターフェース | リソースをURLで識別し、HTTPメソッドで操作 | GET, POST, PUT, DELETEの使い分け |
| 階層化システム | 中間レイヤー(LB, CDN, Gateway)を挿入可能 | スケーラビリティの確保 |
| コードオンデマンド(任意) | サーバーからクライアントにコードを送信可能 | JavaScriptの動的ロード等 |
これらの制約をすべて満たすAPIが「RESTful」と呼ばれるが、実務では厳密なRESTではなく「REST風」のAPIが大半だ。重要なのは教条的にRESTに従うことではなく、「予測可能で、使いやすく、保守しやすいAPI」を設計することだ。
エンドポイント設計
URLの設計原則
| 原則 | 良い例 | 悪い例 |
|---|---|---|
| リソースは名詞(複数形) | /users, /articles | /getUsers, /createArticle |
| 階層構造でリソースの関係を表現 | /users/123/articles | /getUserArticles?userId=123 |
| ケバブケースまたはスネークケース | /user-profiles | /userProfiles, /UserProfiles |
| 動詞はHTTPメソッドで表現 | DELETE /users/123 | POST /deleteUser |
| フィルタ・ソートはクエリパラメータ | /articles?status=published&sort=created_at | /published-articles-sorted-by-date |
HTTPメソッドとCRUD操作
| HTTPメソッド | CRUD | 例 | べき等性 | 安全性 |
|---|---|---|---|---|
| GET | Read | GET /articles/123 | Yes | Yes |
| POST | Create | POST /articles | No | No |
| PUT | Update(全体) | PUT /articles/123 | Yes | No |
| PATCH | Update(部分) | PATCH /articles/123 | No | No |
| DELETE | Delete | DELETE /articles/123 | Yes | No |
「べき等性(Idempotent)」は、同じリクエストを何度送っても結果が同じになる性質だ。GETとPUTとDELETEはべき等。POSTは呼ぶたびに新しいリソースが作られるためべき等ではない。この区別はリトライロジックの設計で重要になる。
レスポンス設計
{
"data": {
"id": "123",
"title": "REST API設計ガイド",
"author": {
"id": "456",
"name": "Taro Yamada"
},
"created_at": "2026-04-18T03:00:00Z",
"updated_at": "2026-04-18T03:00:00Z"
}
}
| 原則 | 説明 |
|---|---|
| データをラッパーオブジェクトに格納 | { "data": {...} } でメタ情報と分離 |
| 日時はISO 8601 | 2026-04-18T03:00:00Z |
| IDは文字列 | JavaScriptのNumber精度問題を回避 |
| ネストは2階層まで | 深いネストはレスポンスの複雑さを増す |
| nullフィールドも明示 | フィールドの有無で型が変わるのを防ぐ |
ページネーション
大量のリソースを返すエンドポイントには必ずページネーションを実装する。
| 方式 | 例 | メリット | デメリット |
|---|---|---|---|
| Offset-based | ?page=2&limit=20 | 実装が簡単、任意ページにジャンプ可能 | 大量データでパフォーマンス低下 |
| Cursor-based | ?cursor=abc123&limit=20 | 大量データでも高性能 | 任意ページへのジャンプ不可 |
| Keyset-based | ?after_id=123&limit=20 | DB効率が良い | ソート順の変更が困難 |
モバイルアプリやSPAの無限スクロールにはCursor-basedが適している。管理画面のテーブル表示にはOffset-basedが直感的だ。
{
"data": [...],
"pagination": {
"total": 150,
"limit": 20,
"offset": 40,
"has_next": true,
"next_cursor": "eyJpZCI6MTIzfQ=="
}
}
HTTPステータスコード
ステータスコードはAPIの「言語」だ。適切に使い分けることで、クライアント側のエラーハンドリングが容易になる。
| コード | 意味 | 使いどころ |
|---|---|---|
| 200 OK | 成功 | GET, PUT, PATCHの成功 |
| 201 Created | リソース作成成功 | POSTの成功 |
| 204 No Content | 成功(レスポンスボディなし) | DELETEの成功 |
| 400 Bad Request | リクエスト不正 | バリデーションエラー |
| 401 Unauthorized | 認証失敗 | トークン未送信・期限切れ |
| 403 Forbidden | 認可失敗 | 権限不足 |
| 404 Not Found | リソースが存在しない | ID不正 |
| 409 Conflict | リソースの競合 | 重複登録、楽観ロック失敗 |
| 422 Unprocessable Entity | セマンティックエラー | バリデーションルール違反 |
| 429 Too Many Requests | レート制限超過 | API呼び出し制限 |
| 500 Internal Server Error | サーバー内部エラー | 予期しない例外 |
エラーレスポンス設計
{
"error": {
"code": "VALIDATION_ERROR",
"message": "入力内容に誤りがあります",
"details": [
{
"field": "email",
"message": "有効なメールアドレスを入力してください"
},
{
"field": "password",
"message": "8文字以上で入力してください"
}
]
}
}
| 原則 | 説明 |
|---|---|
| 機械可読なエラーコード | VALIDATION_ERROR, NOT_FOUND 等 |
| 人間が読めるメッセージ | エラーの内容をわかりやすく |
| フィールドレベルの詳細 | フォームバリデーションで使いやすい |
| スタックトレースは含めない | セキュリティリスクになる |
認証と認可
| 方式 | 特徴 | 適するケース |
|---|---|---|
| API Key | シンプル。ヘッダーまたはクエリパラメータで送信 | サーバー間通信、内部API |
| Bearer Token(JWT) | ステートレス。トークン自体に情報を含む | SPA、モバイルアプリ |
| OAuth 2.0 | 標準的な認可フレームワーク | サードパーティ連携 |
| Session Cookie | 従来型。サーバーサイドに状態を持つ | SSRのWebアプリ |
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
JWTを使う場合の注意点を整理する。
| 注意点 | 理由 |
|---|---|
| 有効期限を短くする(15分〜1時間) | トークン漏洩時のリスク軽減 |
| リフレッシュトークンを使う | アクセストークンの短い有効期限を補う |
| JWTにセンシティブ情報を含めない | Base64デコードで中身が見える |
| HTTPSを必須にする | トークンの盗聴防止 |
| トークンのサイズに注意 | クレームを増やしすぎるとヘッダーが肥大化 |
バージョニング
APIは進化する。後方互換性を壊す変更を行う場合、バージョニングが必要だ。
| 方式 | 例 | メリット | デメリット |
|---|---|---|---|
| URLパス | /v1/users, /v2/users | 明確。デバッグしやすい | URLが冗長 |
| ヘッダー | Accept: application/vnd.api+json;version=2 | URLがクリーン | クライアント実装が複雑 |
| クエリパラメータ | /users?version=2 | 実装が簡単 | キャッシュに影響 |
実務ではURLパス方式が最も一般的だ。URLを見ただけでバージョンが分かるシンプルさが支持されている。
API設計ツールとドキュメント
| ツール | 用途 | 特徴 |
|---|---|---|
| OpenAPI(Swagger) | API仕様の記述 | YAML/JSONでスキーマ定義。業界標準 |
| Swagger UI | APIドキュメントの可視化 | インタラクティブなAPI探索 |
| Postman | API開発・テスト | コレクション共有、自動テスト |
| Redocly | ドキュメント生成 | 美しいドキュメントを生成 |
| Insomnia | API開発・テスト | 軽量。GraphQL対応 |
| Hoppscotch | オープンソースAPI開発 | ブラウザベース。無料 |
OpenAPI仕様を先に定義し、そこからコードを生成する「API First」アプローチが2026年のベストプラクティスだ。フロントエンドとバックエンドが並行開発でき、モックサーバーの自動生成も可能になる。
openapi: 3.1.0
info:
title: Articles API
version: 1.0.0
paths:
/articles:
get:
summary: 記事一覧を取得
parameters:
- name: status
in: query
schema:
type: string
enum: [draft, published]
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/Article'
REST vs GraphQL vs gRPC
RESTは唯一の選択肢ではない。2026年のAPI設計では、GraphQLとgRPCも有力な選択肢だ。
| 比較軸 | REST | GraphQL | gRPC |
|---|---|---|---|
| データ取得 | エンドポイントごとに固定 | クライアントが必要なフィールドを指定 | Protocol Buffers定義 |
| Over-fetching | 発生しうる | なし | なし |
| Under-fetching | 発生しうる(複数リクエスト必要) | なし(1リクエストで完結) | なし |
| リアルタイム | WebSocket別途 | Subscription | ストリーミング |
| 学習コスト | 低い | 中程度 | 高い |
| ツール成熟度 | 最高 | 高い | 中程度 |
| 適するケース | パブリックAPI、CRUD中心 | 複雑なUI、BFF | マイクロサービス間通信 |
RESTを選ぶべきケースは「CRUD操作が中心」「パブリックAPIとして外部に公開する」「チームのGraphQL経験が少ない」場合。GraphQLは「フロントエンドの要件が多様で、必要なデータが画面ごとに大きく異なる」場合に強い。gRPCは「マイクロサービス間の低レイテンシ通信」が求められる場合に適している。
セキュリティのチェックリスト
| チェック項目 | 対策 |
|---|---|
| HTTPSの強制 | すべてのAPIエンドポイントをHTTPS化 |
| 入力バリデーション | すべてのリクエストパラメータを検証 |
| レート制限 | 429 Too Many Requestsで制御 |
| CORS設定 | 許可するオリジンを限定 |
| SQLインジェクション | パラメータライズドクエリ使用 |
| 認証トークンの保護 | HTTPSのみ、Secure Cookie |
| ログに機密情報を含めない | パスワード、トークンはマスク |
| APIキーのローテーション | 定期的な鍵更新の仕組み |
まとめ──良いAPI設計とは
良いAPI設計に共通する特徴を整理する。
| 特徴 | 説明 |
|---|---|
| 予測可能 | URLを見れば何のリソースか分かる |
| 一貫性 | 命名規則、レスポンス形式が統一されている |
| エラーが分かりやすい | ステータスコードとメッセージでデバッグが容易 |
| ドキュメントがある | OpenAPI仕様で自動生成される |
| 後方互換性 | バージョニングで既存クライアントを壊さない |
API設計に「唯一の正解」はない。だが、「使う人の立場で考えられているかどうか」は、良いAPIと悪いAPIを分ける明確な基準だ。自分がAPIの利用者だとしたら、どんなレスポンスが返ってきたら嬉しいか──この視点を持ち続けることが、API設計の質を上げる最短経路ではないだろうか。
