API設計

REST API設計ガイド|わかりやすく使いやすいAPIを作る

API REST 設計

REST API設計ガイド
わかりやすく使いやすいAPIを作る

REST APIの設計原則から、URL設計、HTTPメソッドの使い分け、レスポンス形式、ページネーション、認証まで、良いAPI設計のベストプラクティスを解説します。

こんな人向けの記事です

  • REST APIの設計原則を学びたい
  • わかりやすいURL設計のルールを知りたい
  • エラーレスポンスや認証の設計を理解したい

Step 1RESTとは何か

REST(Representational State Transfer)は、Web APIを設計するためのアーキテクチャスタイルです。HTTPプロトコルの仕組みを最大限活用し、シンプルで直感的なAPIを構築するための原則を定めています。

RESTの6つの原則
1. クライアント-サーバー分離:フロントエンドとバックエンドを独立させる
2. ステートレス:各リクエストは独立し、サーバーはクライアントの状態を保持しない
3. キャッシュ可能:レスポンスにキャッシュの可否を明示する
4. 統一インターフェース:URLとHTTPメソッドで操作を表現する
5. 階層化システム:プロキシやロードバランサーを挟める設計にする
6. コードオンデマンド(任意):必要に応じてクライアントにコードを送る

RESTfulなAPIとそうでないAPIの違いを見てみましょう。

操作RESTfulでない設計RESTfulな設計
ユーザー一覧取得GET /getUsersGET /users
ユーザー作成POST /createUserPOST /users
ユーザー更新POST /updateUser?id=1PUT /users/1
ユーザー削除GET /deleteUser?id=1DELETE /users/1
よくある間違い
URLに動詞を含めるのはRESTの原則に反します。URLは「リソース(名詞)」を表し、操作はHTTPメソッドで表現します。
/getUsers ではなく GET /users が正しい設計です。

Step 2URL設計のベストプラクティス

URLはAPIの「住所」です。一目見て何のリソースを扱っているか分かるように設計します。

基本ルール

ルール良い例悪い例
名詞を使う(動詞は使わない)/articles/getArticles
複数形を使う/users/user
小文字を使う/blog-posts/BlogPosts
ハイフンで単語を区切る/user-profiles/user_profiles
ファイル拡張子を付けない/users/1/users/1.json

リソースの階層構造(ネスト)

リソース間に親子関係がある場合は、URLのパスで関係を表現します。

ネストしたURLの例
# ユーザー1の投稿一覧
GET /users/1/posts

# ユーザー1の投稿5番のコメント一覧
GET /users/1/posts/5/comments

# 投稿5番のコメント3番を取得
GET /users/1/posts/5/comments/3
ネストは2階層までに抑える
3階層以上のネストはURLが長くなりすぎて管理が難しくなります。深いネストが必要な場合は、フラットなURLにクエリパラメータを組み合わせる設計を検討しましょう。

/users/1/posts/5/comments/3/likes よりも
/comments/3/likes の方がシンプルです。

よく使うURLパターン

CRUDのURL設計
# コレクション(一覧)
GET    /api/v1/articles          # 記事一覧を取得
POST   /api/v1/articles          # 記事を新規作成

# 個別リソース
GET    /api/v1/articles/42       # ID=42の記事を取得
PUT    /api/v1/articles/42       # ID=42の記事を全体更新
PATCH  /api/v1/articles/42       # ID=42の記事を部分更新
DELETE /api/v1/articles/42       # ID=42の記事を削除

# サブリソース
GET    /api/v1/articles/42/comments    # 記事42のコメント一覧
POST   /api/v1/articles/42/comments    # 記事42にコメントを追加

# 検索・フィルタリング
GET    /api/v1/articles?category=tech&status=published

Step 3HTTPメソッドの正しい使い分け

HTTPメソッドはリソースに対する操作の種類を表します。正しく使い分けることで、URLを見ただけでAPIの挙動が予測できるようになります。

メソッド操作冪等性リクエストボディ成功時ステータス
GET取得ありなし200 OK
POST作成なしあり201 Created
PUT全体更新ありあり200 OK
PATCH部分更新条件付きあり200 OK
DELETE削除ありなし204 No Content
冪等性(べきとうせい)とは
同じリクエストを何度送っても、結果が同じになる性質のことです。
GET:何度取得しても同じデータが返る(冪等)
DELETE:1回目で削除、2回目以降は404が返るが、サーバーの状態は変わらない(冪等)
POST:送るたびに新しいリソースが作成される(冪等でない)

PUT と PATCH の違い

PUT(全体更新 - すべてのフィールドを送る)
PUT /api/v1/users/1
Content-Type: application/json

{
  "name": "山田太郎",
  "email": "taro@example.com",
  "age": 30,
  "role": "admin"
}
PATCH(部分更新 - 変更するフィールドだけ送る)
PATCH /api/v1/users/1
Content-Type: application/json

{
  "email": "new-taro@example.com"
}
PUTで一部のフィールドだけ送るとどうなる?
PUTは「リソース全体の置き換え」なので、送られなかったフィールドはnullやデフォルト値にリセットされる可能性があります。一部だけ更新したい場合は必ずPATCHを使いましょう。

Step 4レスポンス設計

APIのレスポンスはJSON形式が標準です。成功時もエラー時も一貫した形式で返すことが重要です。

成功レスポンスの設計

単一リソース取得(GET /api/v1/users/1)
{
  "id": 1,
  "name": "山田太郎",
  "email": "taro@example.com",
  "created_at": "2025-01-15T09:30:00Z",
  "updated_at": "2025-06-20T14:00:00Z"
}
コレクション取得(GET /api/v1/users)
{
  "data": [
    {"id": 1, "name": "山田太郎", "email": "taro@example.com"},
    {"id": 2, "name": "佐藤花子", "email": "hanako@example.com"}
  ],
  "meta": {
    "total": 50,
    "page": 1,
    "per_page": 20,
    "total_pages": 3
  }
}
リソース作成成功(POST /api/v1/users → 201 Created)
HTTP/1.1 201 Created
Location: /api/v1/users/3

{
  "id": 3,
  "name": "鈴木一郎",
  "email": "ichiro@example.com",
  "created_at": "2025-07-01T10:00:00Z"
}

エラーレスポンスの設計

エラーレスポンスは、クライアントが何が起きたかどう対処すればいいかが分かるように設計します。

バリデーションエラー(422 Unprocessable Entity)
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "入力内容に問題があります",
    "details": [
      {
        "field": "email",
        "message": "メールアドレスの形式が正しくありません"
      },
      {
        "field": "name",
        "message": "名前は必須です"
      }
    ]
  }
}
認証エラー(401 Unauthorized)
{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "認証トークンが無効または期限切れです"
  }
}
リソース未発見(404 Not Found)
{
  "error": {
    "code": "NOT_FOUND",
    "message": "指定されたユーザーは存在しません"
  }
}
エラーレスポンス設計のポイント
1. HTTPステータスコードを正しく使う:400番台はクライアントエラー、500番台はサーバーエラー
2. エラーコードを一意にするVALIDATION_ERRORのような文字列コードで機械的に判別できるようにする
3. 人間が読めるメッセージを含める:デバッグやユーザー表示に使える
4. フィールド単位のエラーを返す:フォームのどこが間違っているか特定できるようにする

よく使うHTTPステータスコード

コード意味使いどころ
200OKGET/PUT/PATCH成功
201CreatedPOST成功(リソース作成)
204No ContentDELETE成功
400Bad Requestリクエスト形式が不正
401Unauthorized認証が必要
403Forbidden権限不足
404Not Foundリソースが存在しない
422Unprocessable Entityバリデーションエラー
429Too Many Requestsレート制限超過
500Internal Server Errorサーバー内部エラー

Step 5ページネーション・フィルタリング・ソート

大量のデータを返すAPIでは、ページネーション、フィルタリング、ソートの仕組みが不可欠です。これらはすべてクエリパラメータで制御します。

ページネーション

主に2つの方式があります。

方式パラメータ例特徴
オフセット方式?page=2&per_page=20シンプル、ページジャンプ可能。大量データで遅くなる
カーソル方式?cursor=abc123&limit=20高パフォーマンス。ページジャンプ不可
オフセット方式のリクエストとレスポンス
# リクエスト
GET /api/v1/articles?page=2&per_page=10

# レスポンス
{
  "data": [...],
  "meta": {
    "total": 95,
    "page": 2,
    "per_page": 10,
    "total_pages": 10
  },
  "links": {
    "first": "/api/v1/articles?page=1&per_page=10",
    "prev": "/api/v1/articles?page=1&per_page=10",
    "next": "/api/v1/articles?page=3&per_page=10",
    "last": "/api/v1/articles?page=10&per_page=10"
  }
}
カーソル方式のリクエストとレスポンス
# リクエスト(次ページ)
GET /api/v1/articles?cursor=eyJpZCI6MjB9&limit=10

# レスポンス
{
  "data": [...],
  "meta": {
    "has_next": true,
    "next_cursor": "eyJpZCI6MzB9"
  }
}
どちらの方式を選ぶべきか
オフセット方式:管理画面、ブログ一覧など「ページ番号が必要」な場合
カーソル方式:SNSのタイムライン、チャット履歴など「無限スクロール」の場合
データ量が数万件を超える場合はカーソル方式が推奨されます。

フィルタリング

フィルタリングの例
# カテゴリで絞り込み
GET /api/v1/articles?category=tech

# 複数条件で絞り込み
GET /api/v1/articles?category=tech&status=published

# 日付範囲で絞り込み
GET /api/v1/articles?created_after=2025-01-01&created_before=2025-12-31

# 検索
GET /api/v1/articles?search=REST+API

ソート

ソートの例
# 作成日の降順(新しい順)
GET /api/v1/articles?sort=-created_at

# タイトルの昇順
GET /api/v1/articles?sort=title

# 複合ソート(カテゴリ昇順 → 作成日降順)
GET /api/v1/articles?sort=category,-created_at
ソートの慣習
フィールド名の先頭に -(マイナス)を付けると降順を表すのが一般的な慣習です。Django REST Frameworkでもこの形式が使われています。

組み合わせ例

フィルタリング + ソート + ページネーション
# 公開済みの技術記事を新しい順に、1ページ10件で2ページ目を取得
GET /api/v1/articles?category=tech&status=published&sort=-created_at&page=2&per_page=10

Step 6バージョニングと認証

本番環境で長期運用するAPIでは、バージョン管理認証の設計が不可欠です。

APIバージョニング

APIの仕様を変更する際、既存のクライアントを壊さないためにバージョンを管理します。

方式メリットデメリット
URLパス方式/api/v1/users直感的で分かりやすいURLが変わる
ヘッダー方式Accept: application/vnd.api+json;version=1URLがクリーン見えにくい
クエリパラメータ方式/api/users?version=1実装が簡単キャッシュに不利
おすすめはURLパス方式
/api/v1/ の形式が最も広く使われています。GitHub、Stripe、Twitterなど主要なAPIサービスがこの方式を採用しています。シンプルで、ブラウザから直接テストしやすいのが利点です。
Django REST Frameworkでのバージョニング設定
# settings.py
REST_FRAMEWORK = {
    'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',
    'DEFAULT_VERSION': 'v1',
    'ALLOWED_VERSIONS': ['v1', 'v2'],
}

# urls.py
urlpatterns = [
    path('api/<version>/users/', UserListView.as_view()),
]

認証方式の比較

方式仕組み適したケース
API Key固定のキーをヘッダーに付与サーバー間通信、シンプルなAPI
OAuth 2.0認可サーバー経由でトークンを発行サードパーティ連携(Google, GitHub等)
JWT署名付きトークンで認証情報を伝達SPA、モバイルアプリ

API Key 認証

API Keyをヘッダーで送信
curl -H "X-API-Key: your-api-key-here"   https://api.example.com/v1/users

JWT(JSON Web Token)認証

JWTの認証フロー
# 1. ログインしてトークンを取得
POST /api/v1/auth/login
Content-Type: application/json

{
  "email": "taro@example.com",
  "password": "secure-password"
}

# レスポンス
{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "refresh_token": "eyJhbGciOiJIUzI1NiIs...",
  "expires_in": 3600
}

# 2. トークンを使ってAPIにアクセス
GET /api/v1/users/me
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
JWT運用時の注意点
1. アクセストークンの有効期限は短く(15分〜1時間)設定する
2. リフレッシュトークンで新しいアクセストークンを再取得する仕組みを用意する
3. JWTにパスワードなどの機密情報を含めない(Base64でデコードすると中身が読める)
4. HTTPS必須 - トークンが平文で送られるため、HTTPでは盗聴される

OAuth 2.0 認証

OAuth 2.0 認可コードフロー
# 1. ユーザーを認可エンドポイントにリダイレクト
GET https://auth.example.com/authorize
  ?response_type=code
  &client_id=your-client-id
  &redirect_uri=https://your-app.com/callback
  &scope=read+write

# 2. コールバックで認可コードを受け取る
GET https://your-app.com/callback?code=abc123

# 3. 認可コードをアクセストークンに交換
POST https://auth.example.com/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=abc123
&client_id=your-client-id
&client_secret=your-client-secret
&redirect_uri=https://your-app.com/callback
認証方式の選び方
内部APIや単純なサービス → API Key
ユーザーログインが必要なSPA/モバイルアプリ → JWT
他サービスとの連携(GitHub, Google等) → OAuth 2.0
複数の認証方式を組み合わせることも一般的です。

まとめ

  • RESTはHTTPの仕組みを活用したAPI設計のアーキテクチャスタイル
  • URLはリソース(名詞・複数形)で表現し、操作はHTTPメソッドで区別する
  • PUT(全体更新)とPATCH(部分更新)を正しく使い分ける
  • 成功もエラーも一貫したJSON形式で返し、適切なステータスコードを使う
  • ページネーション・フィルタリング・ソートはクエリパラメータで制御する
  • バージョニングはURLパス方式が主流、認証はJWTまたはOAuth 2.0が一般的