REST API完全ガイド:設計原則・HTTPセマンティクス・セキュリティと実践ベストプラクティス

REST API とは — 概要

REST(Representational State Transfer)は、2000年にロイ・フィールディング(Roy Fielding)が博士論文で提唱したソフトウェアアーキテクチャのスタイルで、特にWeb上の分散システム設計に適しています。REST APIは、このアーキテクチャ原則に沿って設計されたAPIのことを指し、HTTPの既存の機能(URI、メソッド、ステータスコード、ヘッダ、メディア型など)を利用してクライアントとサーバ間の通信を行います。

REST の定義と主要な制約(Constraints)

RESTはプロトコルそのものではなく設計原則の集合です。FieldingはRESTを満たすために以下の6つ(うち1つは任意)の制約を挙げています。これらを満たすことで、スケーラブルで拡張可能、かつ保守しやすいシステム設計を目指します。

  • クライアント–サーバ(Client–Server):責務の分離。ユーザーインターフェースとデータストレージの分離により、独立した進化が可能。
  • ステートレス(Stateless):各リクエストはサーバ側にクライアントのセッション状態を保持しない(必要な情報は各リクエストに含める)。これによりスケーリングと障害復旧が容易になる。
  • キャッシュ可能(Cacheable):レスポンスが明示的にキャッシュ可能かどうかを示し、再利用を促進することでパフォーマンスを向上。
  • 統一インターフェース(Uniform Interface):システムの単純化と相互運用性の向上を目的とし、リソースの識別、リソース表現、自己記述メッセージ、ハイパーメディア(HATEOAS)の4つの要素を含む。
  • 階層化システム(Layered System):中間層(ロードバランサ、キャッシュ、ゲートウェイなど)を導入でき、クライアントは最終エンドポイントを直接認識しなくてよい。
  • コードオンデマンド(Code on Demand) — 任意:サーバがクライアントにスクリプトやコードを送信して機能を拡張できる(例:JavaScript)。任意なので必須ではない。

HTTP と REST の関係

RESTはHTTPを前提とすることが多く、URIでリソースを識別し、HTTPメソッド(GET、POST、PUT、PATCH、DELETEなど)で操作を表現します。重要なのは、HTTPの意味(セマンティクス)を尊重することです。例えばGETは「安全(safe)」かつ「副作用のない」読み取り操作を意味し、PUTやDELETEは冪等(idempotent)であることが期待されます(RFC 7231に詳述)。

リソース設計 — URI、表現、メディアタイプ

  • URI設計の基本

    URIは操作を表すのではなく「リソース」を表すべきです。一般的な慣習としては名詞の複数形を使い、階層的にネストして関係性を表現します。例:/users、/users/{userId}/orders。

  • 表現(Representation)

    リソースは様々な表現(JSON、XML、HTMLなど)で表されます。実務ではJSONが最も一般的です。表現はリソース状態のスナップショットであり、適切なメディアタイプ(Content-Type)で返却されます。

  • コンテンツネゴシエーション

    クライアントはAcceptヘッダで希望するメディアタイプを示し、サーバは応答する表現を選択できます(例:application/json、application/xml)。

代表的なHTTPメソッドと使い分け

  • GET — リソースの取得(安全かつ冪等)。レスポンスはキャッシュ可能であることが多い。
  • POST — 新規リソース作成やサーバ側での処理実行(非冪等)。サブミッションや検索(複雑なクエリ)に使われることもある。
  • PUT — 指定したURIにリソースを完全に置換(冪等)。存在しなければ作成する場合もある。
  • PATCH — リソースの部分更新(部分的な変更、通常は冪等でない場合もあるが設計次第)。
  • DELETE — リソースの削除(冪等)。

状態コード(HTTP Status Codes)の運用例

正しいステータスコードの使用はクライアントとサーバの協調に重要です。頻出の例:

  • 200 OK — 成功(GET, PUTなど)。
  • 201 Created — リソース作成に成功(POST)。Locationヘッダで作成URIを返す。
  • 204 No Content — 成功だがレスポンスボディなし(DELETEやPUTの成功時に利用)。
  • 400 Bad Request — リクエストが不正(バリデーションエラーなど)。
  • 401 Unauthorized — 認証が必要。
  • 403 Forbidden — 認可されていない操作。
  • 404 Not Found — リソースが存在しない。
  • 409 Conflict — 競合(例:重複作成やバージョン競合)。
  • 429 Too Many Requests — レート制限に達した。
  • 5xx — サーバ内部エラー。

実践的な設計パターンとベストプラクティス

  • リソースの命名

    URIはわかりやすく、予測可能に。動詞ではなく名詞、複数形を推奨。例:/articles、/users/{id}/orders。

  • フィルタリング、ソート、ページング

    大量データの取り扱いにはクエリパラメータを使用:?page=2&limit=20、?sort=-created_at、?status=published といった形。

  • 部分更新の選択(PATCH vs PUT)

    部分更新にはPATCH(JSON Patch, JSON Merge Patchなどの仕様を明確に)。PUTは完全置換を念頭に。

  • 冪等性と安全性

    クライアントは再試行による副作用を考慮する。PUTやDELETEは冪等であるよう設計し、POSTは非冪等であることを許容する。

  • ハイパーメディア(HATEOAS)

    リソース表現に次に取るべきアクションへのリンクを含め、クライアントを導く設計。ただし実務では完全なHATEOASを採用するケースは限定的で、多くはリンクやURIテンプレートのみを部分的に利用する。

  • 一貫したエラー表現

    エラーは構造化されたJSONで返す(例:{ "status": 400, "error": "Bad Request", "message": "...", "errors": [...] })。API利用者が解析しやすい形に。

認証・認可とセキュリティ

REST APIのセキュリティは非常に重要です。代表的な手法を挙げます。

  • TLS(HTTPS):常時TLSを利用し、通信を暗号化する。プレーンHTTPは避ける。
  • APIキー:簡易的な認証。サーバ側でキーを発行し、ヘッダやクエリで送信(ただし露出リスクあり)。
  • OAuth 2.0:第三者認可やアクセストークン発行に広く利用される(RFC 6749)。
  • JWT(JSON Web Tokens):自己完結型トークン。署名により改ざん検知が可能だが、失効管理は注意が必要。
  • CORS(Cross-Origin Resource Sharing):ブラウザ利用時のオリジン制御。許可されたオリジンやメソッドのみを許可する。
  • CSRF対策:ブラウザからの状態変更リクエストに対する保護。トークンベースの設計やSameSiteクッキーの利用。
  • 入力検証と出力エスケープ:SQLインジェクションやXSS、その他の脆弱性対策を徹底する。OWASP API Security Top 10 などを参照。

キャッシュとパフォーマンス

キャッシュはパフォーマンス向上とスケーラビリティの鍵です。HTTPのCache-Control、ETag、Last-Modified、Expiresなどのヘッダを適切に設定することで、不要なリクエストを減らせます。ステートレス設計とあわせてロードバランシング、CDNの利用、バックエンドでのページングやインデックス設計も重要です。

エラーハンドリング、バージョニング、互換性

  • エラーハンドリング:一貫したエラー形式、適切なステータスコード、詳細は開発者向けドキュメントで明示。
  • バージョニング:互換性を保つためにAPIの変更管理が必須。一般的手法は
    • URIバージョン(/v1/users)
    • ヘッダによるバージョン(Accept: application/vnd.example.v1+json)
    • クエリパラメータ(?version=1)(実務ではあまり推奨されない)
  • 後方互換性の維持:可能な限り非破壊的な変更(フィールド追加はOK、削除や意味変更はNG)。破壊的変更は新バージョンで提供。

ドキュメンテーションとツール

良いAPIは良いドキュメントを持ちます。OpenAPI(旧Swagger)などの仕様を使えば、機械可読なAPI定義からドキュメントやクライアントSDKを自動生成できます。Postmanやcurl、APIゲートウェイ(AWS API Gatewayなど)を用いたテスト/監視も標準的です。テストはユニット、統合、契約テスト(consumer-driven contract)を組み合わせると堅牢です。

REST の限界と代替アプローチ

RESTは広く使われていますが万能ではありません。複数リソースを横断して必要なデータを1回のクエリで取得したい場合、RESTだと複数リクエストが必要になることがあります。こうした場面ではGraphQLのようなクライアント主導のクエリ言語が有効です。また、高度なストリーミングや双方向通信(リアルタイム)にはWebSocketやgRPCのようなプロトコルが適しています。設計はユースケースに応じて選択すべきです。

実用的な例(簡易)

ユーザーリソースを扱う典型的なエンドポイント例:

  • GET /users — ユーザー一覧(フィルタ、ソート、ページング対応)
  • POST /users — ユーザー作成(201 Created、Locationヘッダに /users/{id})
  • GET /users/{id} — 指定ユーザー取得(200)
  • PUT /users/{id} — 指定ユーザーを完全更新(200または204)
  • PATCH /users/{id} — 指定ユーザーを部分更新(200)
  • DELETE /users/{id} — 指定ユーザー削除(204)

例:ユーザー作成のレスポンス(201)

HTTP/1.1 201 Created
Location: https://api.example.com/users/123
Content-Type: application/json

{
  "id": 123,
  "name": "山田 太郎",
  "email": "taro@example.com"
}

まとめ — 守るべきポイント

  • RESTはアーキテクチャスタイルであり、設計原則(ステートレス、キャッシュ、統一インターフェースなど)を理解することが重要。
  • HTTPのセマンティクスを尊重し、適切なメソッドとステータスコードを使用する。
  • セキュリティ(TLS、認証・認可、入力検証)は最優先で設計する。
  • ドキュメンテーション(OpenAPI等)と一貫したエラー形式、バージョニング戦略を用意する。
  • ユースケースに応じてREST以外の技術(GraphQL、gRPC、WebSocketなど)を検討する柔軟性も持つ。

参考文献