「社内システムと外部サービスを連携させたい」「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は、システムの拡張性を高め、開発コストを削減し、将来的な事業成長を支える重要な基盤となります。この記事で紹介したベストプラクティスを参考に、まずは小さく始めてみましょう。