REST API設計のベストプラクティス完全ガイド|初心者でも実践できる基本と応用

kento_morota 20分で読めます

「社内システムと外部サービスを連携させたい」「API設計の品質が開発スピードやメンテナンス性に影響すると聞くが、何を基準に設計すればいいのかわからない」――そんな課題を抱えている方に向けて、REST API設計の基本と実践的なベストプラクティスを紹介します。

本記事では、URL設計や命名規則、エラーハンドリングなど、実務で使える具体例を交えながら、品質の高いAPI設計のポイントを初心者にもわかりやすく解説します。

REST APIとは?設計の基本を理解しよう

「システム同士がどうやってデータをやり取りするのか」という課題に直面していませんか?REST APIは、異なるシステム間でデータを安全かつ効率的に送受信するための仕組みです。

適切に設計されたREST APIは、システムの拡張性を高め、開発コストを削減し、将来的な事業成長を支える重要な基盤となります。TypeScriptプロジェクトではtRPCによる型安全なAPI構築も注目されています。この記事では、REST API設計のベストプラクティスを基礎から実践まで解説します。

REST APIの基本原則

REST(Representational State Transfer)は、Webの仕組みを最大限に活用した設計思想です。GraphQLとの比較はGraphQLとREST APIの違いをご覧ください。以下の4つの原則で構成されます。

リソース指向のアーキテクチャ
すべての情報を「リソース」として扱います。顧客情報、商品データ、注文履歴など、それぞれが独立したリソースとして管理され、一意のURLでアクセスします。

ステートレスな通信
サーバー側はクライアントの状態を保持しません。認証の仕組みについてはOAuth2.0認証の解説も参考になります。各リクエストは完全に独立しており、必要な情報はすべてリクエストに含まれます。これにより、複数のサーバーで負荷分散しやすくなります。

統一されたインターフェース
HTTPメソッド(GET、POST、PUT、DELETEなど)を標準的な方法で使用します。この統一性により、開発者は直感的にAPIの使い方を理解できます。

階層化されたシステム
クライアントとサーバーの間に、キャッシュサーバーやロードバランサーなどの中間層を配置できます。

なぜREST APIが選ばれるのか

REST APIが業界標準として定着している理由は3つあります。

既存のWeb技術を活用できる
HTTPプロトコルやJSON形式など、確立された技術を使うため、学習コストが低く抑えられます。多くのプログラミング言語やフレームワークがサポートしており、開発環境を選びません。

シンプルで理解しやすい
URLとHTTPメソッドの組み合わせという直感的な構造です。新しいメンバーがチームに加わった際も、比較的短期間でキャッチアップできます。

段階的な拡張が可能
最初は小規模なシステムから始めて、ビジネスの成長に合わせて機能を追加できます。中小企業にとって「ちょうどいい」規模感で始められる点が魅力です。

設計前に明確にすべきこと

実際の設計に入る前に、以下のポイントを整理しましょう。

ビジネス要件の整理
何のためにAPIを作るのかを明確にします。社内システム間の連携、外部パートナーへのデータ提供、一般ユーザー向けのサービスなど、目的によってセキュリティレベルや必要な機能が変わります。

対象ユーザーの特定
APIを利用するのは誰でしょうか。社内の開発者、取引先の技術者、外部の開発者コミュニティ。ユーザーの技術レベルに応じて、ドキュメントの詳細度を調整します。

データモデルの設計
どのようなデータを扱うのか、データ間の関係性はどうなっているのかを整理します。顧客と注文の関係、商品とカテゴリーの関係など、ビジネスロジックを反映したデータ構造を事前に設計することで、一貫性のあるAPI設計が可能になります。

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

REST API設計において、URLの設計は最も基本的かつ重要な要素です。適切に設計されたURLは、APIの使いやすさを大きく左右します。

リソース指向のURL設計

REST APIのURLは「リソース」を表現し、「アクション(動作)」は表現しません。これが最も重要な原則です。

良い例:リソースを名詞で表現

GET /api/customers          # 顧客一覧の取得
GET /api/customers/123      # 特定顧客の取得
POST /api/orders            # 注文の作成
DELETE /api/products/456    # 商品の削除

悪い例:動詞を含むURL

GET /api/getCustomers       # ×
POST /api/createOrder       # ×

動詞はHTTPメソッドで表現します。これにより、同じリソースに対する異なる操作を統一されたインターフェースで実現できます。

階層構造でリソース間の関係を表現
リソース間の親子関係は、URLの階層構造で表現します。ただし、階層は2階層までを推奨します。

GET /api/customers/123/orders        # 顧客123の注文一覧
GET /api/orders/789/items            # 注文789の商品明細

3階層以上になる場合は、クエリパラメータを活用します。

# 深すぎる階層(非推奨)
GET /api/customers/123/orders/789/items/456

# 改善案
GET /api/order-items/456
GET /api/items?orderId=789

命名規則の統一

URL設計における命名規則は、チーム内で統一することが重要です。

ケバブケース(推奨)
URLには、単語をハイフンで区切るケバブケースを使用します。

/api/customer-orders
/api/product-categories

ケバブケースが推奨される理由:
- すべて小文字で統一でき、大文字小文字の混乱を避けられる
- 可読性が高く、人間が読みやすい
- SEOの観点からも推奨されている

JSONプロパティはキャメルケース
レスポンスのJSON内では、キャメルケースを使用します。

{
  "customerId": 123,
  "firstName": "太郎",
  "emailAddress": "taro@example.com"
}

複数形の使用

コレクション(リソースの集合)を表す場合も、個別のリソースを表す場合も、複数形で統一します。

GET /api/customers          # コレクション
GET /api/customers/123      # 個別リソース
POST /api/customers         # 新規作成
PUT /api/customers/123      # 更新
DELETE /api/customers/123   # 削除

すべて複数形で統一することで、開発者の認知負荷が下がり、エラーも減少します。

例外:単数形を使うケース
ログイン中のユーザー自身の情報など、常に単一のリソースを指す場合は単数形を使うこともあります。

GET /api/profile        # ログイン中のユーザープロフィール
GET /api/settings       # ログイン中のユーザー設定

HTTPメソッドの正しい使い方

HTTPメソッドは、リソースに対してどのような操作を行うかを示す重要な要素です。適切に使い分けることで、予測可能で保守しやすいAPIを実現できます。

各メソッドの役割と使い分け

GET:リソースの取得
データの読み取り専用操作に使用します。サーバーの状態を変更しません。

GET /api/customers              # 顧客一覧の取得
GET /api/customers/123          # 特定顧客の取得
GET /api/orders?status=pending  # 条件付き検索

GETの特徴:
- リクエストボディは使用しない
- キャッシュ可能
- 冪等性と安全性がある

POST:リソースの新規作成
新しいリソースを作成する際に使用します。

POST /api/customers
Content-Type: application/json

{
  "firstName": "太郎",
  "lastName": "山田",
  "email": "taro@example.com"
}

成功時は201 Createdを返し、Locationヘッダーに新規リソースのURLを含めます。

PUT:リソースの完全な置き換え
既存リソース全体を新しいデータで置き換えます。リソース全体のデータを送信する必要があり、冪等性があります。

PUT /api/customers/123
Content-Type: application/json

{
  "firstName": "太郎",
  "lastName": "山田",
  "email": "taro.yamada@example.com",
  "phone": "03-1234-5678"
}

PATCH:リソースの部分的な更新
リソースの一部のフィールドだけを更新します。PUTより効率的で、実務では頻繁に使用されます。

PATCH /api/customers/123
Content-Type: application/json

{
  "email": "new.email@example.com"
}

DELETE:リソースの削除
指定したリソースを削除します。冪等性があり、成功時は204 No Contentまたは200 OKを返します。

DELETE /api/customers/123

冪等性と安全性の理解

冪等性(idempotency)
同じ操作を何度実行しても、結果が変わらない性質のことです。

  • 冪等なメソッド:GET、PUT、DELETE、PATCH
  • 非冪等なメソッド:POST

ネットワークエラーやタイムアウトが発生した場合、クライアントは同じリクエストを再送信することがあります。冪等性が保証されていれば、安全にリトライできます。

非冪等操作への対策
POSTなど非冪等な操作では、クライアント側で生成した一意のIDを送信する方法があります。

POST /api/orders
Content-Type: application/json

{
  "idempotencyKey": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "customerId": 123,
  "items": [...]
}

サーバー側で同じidempotencyKeyのリクエストを検出し、重複処理を防ぎます。

安全性(safe)
GETとHEADは「安全」なメソッドとされ、サーバーの状態を変更しません。この性質により、キャッシュを積極的に活用できます。

頻繁に変更されないデータには長めのキャッシュ期間を設定し、リアルタイム性が求められるデータにはキャッシュを無効化またはETagを使った条件付きリクエストを活用します。

ステータスコードとエラーハンドリング

適切なHTTPステータスコードとエラーメッセージは、APIの使いやすさを大きく左右します。

主要なステータスコードの使い分け

2xx:成功
- 200 OK:リクエストが成功し、レスポンスボディにデータを返す
- 201 Created:新しいリソースが作成された(Locationヘッダーを含める)
- 204 No Content:成功したがレスポンスボディは空

4xx:クライアントエラー
- 400 Bad Request:リクエストの形式が不正(JSONの構文エラー、必須フィールドの欠落など)
- 401 Unauthorized:認証が必要、または認証情報が無効
- 403 Forbidden:認証は成功したが、権限がない
- 404 Not Found:リソースが存在しない
- 409 Conflict:リソースの状態と競合する(重複したメールアドレスなど)
- 422 Unprocessable Entity:リクエストは理解できるが、ビジネスロジックで処理できない
- 429 Too Many Requests:レート制限を超過

5xx:サーバーエラー
- 500 Internal Server Error:サーバー側の予期しないエラー
- 503 Service Unavailable:一時的にサービスが利用できない

エラーレスポンスの設計

一貫性のあるエラーレスポンス形式を定義することで、クライアント側でのエラーハンドリングが容易になります。

基本的なエラーレスポンス構造

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "入力内容に誤りがあります",
    "details": [
      {
        "field": "email",
        "message": "メールアドレスの形式が正しくありません"
      },
      {
        "field": "age",
        "message": "年齢は0以上の数値を入力してください"
      }
    ],
    "timestamp": "2024-01-15T10:30:00Z",
    "path": "/api/customers"
  }
}

推奨される要素
1. code:機械可読なエラーコード
2. message:人間が読むエラーメッセージ
3. details:詳細情報(特にバリデーションエラー時)
4. timestamp:エラー発生時刻
5. path:エラーが発生したエンドポイント

ユーザーフレンドリーなエラーメッセージ

エラーメッセージは、問題の原因と解決方法を明確に伝えるべきです。

良い例

{
  "error": {
    "code": "AUTHENTICATION_FAILED",
    "message": "認証に失敗しました。APIキーが無効か、有効期限が切れています。",
    "hint": "APIキーを確認するか、新しいキーを発行してください。"
  }
}

エラーメッセージ作成のポイント
- 具体的に何のエラーかを明示
- なぜエラーになったのかを説明
- どうすれば解決できるかを示唆
- 専門用語を避け、理解しやすい表現を心がける

セキュリティとエラーメッセージ
セキュリティ上の理由から、詳細を明かしすぎないバランスも重要です。

# 悪い例:情報漏洩のリスク
"User 'admin' does not exist in database table 'users'"

# 良い例:必要な情報のみ
"ユーザー名またはパスワードが正しくありません"

データ形式とレスポンス設計

JSONレスポンスの基本構造

REST APIのレスポンスは、一貫性のある構造を持つべきです。

単一リソースのレスポンス

{
  "id": 123,
  "firstName": "太郎",
  "lastName": "山田",
  "email": "taro@example.com",
  "createdAt": "2024-01-15T10:30:00Z",
  "updatedAt": "2024-01-20T15:45:00Z"
}

コレクションのレスポンス

{
  "data": [
    {
      "id": 123,
      "firstName": "太郎",
      "lastName": "山田"
    },
    {
      "id": 124,
      "firstName": "花子",
      "lastName": "佐藤"
    }
  ],
  "meta": {
    "total": 150,
    "page": 1,
    "pageSize": 20,
    "totalPages": 8
  }
}

ページネーションの実装

大量のデータを返す場合、ページネーションは必須です。

クエリパラメータによるページネーション

GET /api/customers?page=2&pageSize=20

レスポンス例

{
  "data": [...],
  "meta": {
    "page": 2,
    "pageSize": 20,
    "total": 150,
    "totalPages": 8
  },
  "links": {
    "first": "/api/customers?page=1&pageSize=20",
    "prev": "/api/customers?page=1&pageSize=20",
    "next": "/api/customers?page=3&pageSize=20",
    "last": "/api/customers?page=8&pageSize=20"
  }
}

フィルタリングとソート

フィルタリング

GET /api/orders?status=pending&customerId=123
GET /api/products?category=electronics&minPrice=10000

ソート

GET /api/customers?sortBy=createdAt&order=desc
GET /api/products?sortBy=price&order=asc

複合条件

GET /api/orders?status=pending&sortBy=createdAt&order=desc&page=1&pageSize=20

セキュリティとバージョニング

認証・認可の基本設計

認証(Authentication)
ユーザーが誰であるかを確認するプロセスです。

認可(Authorization)
認証されたユーザーが何をできるかを制御するプロセスです。

APIキーとトークンベース認証

APIキー認証
シンプルで実装しやすいですが、セキュリティレベルは中程度です。

GET /api/customers
Authorization: ApiKey your-api-key-here

トークンベース認証(JWT)
より高いセキュリティレベルが求められる場合に使用します。

GET /api/customers
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

バージョニング戦略

APIは進化します。後方互換性を保ちながら新機能を追加するため、バージョニングが必要です。

URLパスによるバージョニング(推奨)

GET /api/v1/customers
GET /api/v2/customers

明示的で分かりやすく、最も広く使われている方法です。

ヘッダーによるバージョニング

GET /api/customers
Accept: application/vnd.company.v2+json

URLを変更せずにバージョン管理できますが、やや複雑です。

後方互換性を保つための工夫
- 既存のフィールドは削除せず、非推奨(deprecated)として残す
- 新しいフィールドは追加のみ
- 破壊的変更は新しいバージョンで提供
- 古いバージョンのサポート期間を明示

実務で役立つ設計チェックリスト

REST API設計の最終チェックポイント

URL設計
- [ ] リソースは名詞で表現されているか
- [ ] 動詞がURLに含まれていないか
- [ ] ケバブケースで統一されているか
- [ ] 複数形で統一されているか
- [ ] 階層は2階層以内か

HTTPメソッド
- [ ] GET、POST、PUT、PATCH、DELETEを適切に使い分けているか
- [ ] 冪等性を考慮しているか
- [ ] GETでサーバーの状態を変更していないか

ステータスコード
- [ ] 適切なステータスコードを返しているか
- [ ] エラーレスポンスは一貫した形式か
- [ ] エラーメッセージは分かりやすいか

セキュリティ
- [ ] 認証・認可が適切に実装されているか
- [ ] 機密情報がログに出力されていないか
- [ ] レート制限が設定されているか

ドキュメント
- [ ] エンドポイントの説明が明確か
- [ ] リクエスト/レスポンスの例があるか
- [ ] エラーコードの一覧があるか

小規模から始めるAPI設計のススメ

最初から完璧を目指す必要はありません。MVP(Minimum Viable Product)の考え方で、まず必要最小限の機能を実装し、フィードバックを得ながら改善していく方が、実務では成功しやすいです。

ステップ1:コアな機能から始める
最も重要な1〜2つのリソースだけを実装します。

ステップ2:フィードバックを収集
実際に使ってもらい、改善点を洗い出します。

ステップ3:段階的に拡張
ビジネスの成長に合わせて、機能を追加していきます。

適切に設計されたREST APIは、システムの拡張性を高め、開発コストを削減し、将来的な事業成長を支える重要な基盤となります。この記事で紹介したベストプラクティスを参考に、まずは小さく始めてみましょう。

#REST#API#設計
共有:

ちょっとした業務の悩みも、気軽にご相談ください。

まずは話だけ聞いてもらう