REST APIの作り方:設計、セキュリティ、デプロイ
REST APIを作るには、アプリが管理するリソース(ユーザー、注文、予約など)を書き出し、それぞれに/ordersや/orders/{id}のようなURLを付け、操作にはHTTPメソッドを使います。GETで読み取り、POSTで作成、PATCHで更新、DELETEで削除です。適切なステータスコードを付けてJSONを返し、すべての入力を検証し、認証とレコード単位の権限チェックをサーバー側で行い、一覧はページ分割してください。その後、エンドポイントをドキュメント化し、HTTPSの背後にAPIをデプロイします。
このガイドでは、設計上の判断、ルートの具体例、AIアプリビルダーへのプロンプト、そしてセキュリティ上の穴につながる典型的なミスを扱います。APIに不慣れな場合は、まずAPIとは何かから始めてください。
REST APIが必要になるとき
- Webフロントエンドが、サーバーとデータを保存・読み込みする必要がある
- モバイルアプリ、パートナー、自動化ツールがデータにアクセスする必要がある
- 他のサービスがイベントを送ってくる(Webhook)
- フロントエンドとバックエンドのチームで作業を分担している
RESTは最も一般的なスタイルですが、唯一の選択肢ではありません。単一の柔軟なクエリエンドポイントが適している場合は、RESTとGraphQLで解説しています。
設計が先:リソースとルート
アプリ内の名詞と、それに対してユーザーが行うことを書き出します。シンプルな予約アプリの例は次のとおりです。
| メソッド | ルート | 役割 | 成功時のコード |
|---|---|---|---|
GET | /api/bookings | 呼び出し元の予約を一覧表示(ページ分割) | 200 |
POST | /api/bookings | 予約を作成 | 201 |
GET | /api/bookings/{id} | 予約を1件取得 | 200 |
PATCH | /api/bookings/{id} | 一部のフィールドを変更 | 200 |
DELETE | /api/bookings/{id} | 予約をキャンセル | 204 |
GET | /api/health | 監視用のヘルスチェック | 200 |
これらは作成・読み取り・更新・削除(CRUD)に対応します。詳しくはCRUDとはを参照してください。守るとよい慣習は次のとおりです。
- URLには複数形の名詞を使い、動詞は使わない:
/getBookingsではなく/bookings - 所有関係が分かりやすくなる場合のみ、1階層だけネストする:
/bookings/{id}/notes - CRUDに当てはまらない操作はサブリソースにできる:マジックなPATCHより
POST /bookings/{id}/cancelの方が明確 - フィールド名は一貫させる:どこでも
created_atなど
ステータスコードとエラー
標準のHTTPコードを使うと、クライアントはテキストを解析しなくても結果を把握できます。
| コード | 意味 | 使う場面 |
|---|---|---|
| 200 | OK | 読み取りや更新が成功 |
| 201 | Created | POSTで何かが作成された |
| 204 | No Content | 成功したが返すものがない |
| 400 | Bad Request | 入力が検証に失敗 |
| 401 | Unauthorized | ログインしていない、またはトークンが無効 |
| 403 | Forbidden | ログイン済みだが許可されていない |
| 404 | Not Found | 存在しない、または存在を呼び出し元に知らせてはいけない |
| 409 | Conflict | 重複、または枠がすでに予約済み |
| 429 | Too Many Requests | レート制限に達した |
| 500 | Server Error | サーバー側で問題が発生 |
エラーは一貫したJSON形式で返してください。例:{"error": {"code": "slot_taken", "message": "その時間はもう利用できません。"}}。レスポンスにスタックトレースやデータベースのエラーを決して含めないでください。
選択肢とトレードオフ
| 判断 | シンプルな選択 | 代替案 |
|---|---|---|
| APIの置き場所 | Webフレームワーク内のAPIルート | 複数のクライアントや別の言語に向く、独立したAPIサービス |
| 認証 | 自分のWebアプリ向けのセッションCookie | モバイルアプリやサードパーティ向けのトークン(Bearerトークンまたは APIキー) |
| ページ分割 | ?page=2&limit=20 | カーソル方式(?after=...)。大規模で変化する一覧に安定 |
| バージョニング | 外部ユーザーが現れるまでは不要 | 他者が依存するようになったら、パスに/v1/を付ける |
| ドキュメント | ルートを列挙したREADME | OpenAPI仕様。ツールが対話型ドキュメントやクライアントコードを生成できる |
手順
- リソースとルートを列挙する(上記のとおり、誰が呼び出せるかも含める)。
- データをモデル化する:必要なフィールドとリレーションをデータベースに定義する。
- 読み取りルートを先に作り、その後に作成・更新・削除を作る。
- すべての書き込みで入力を検証する:スキーマライブラリを使い、必須項目、型、長さ、許可された値を確認する。未知のフィールドは拒否する。
- 認証を追加し、次にレコード単位の認可を追加する:
/bookings/42を読み込むとき、ログインしているだけでなく、予約42が呼び出し元のものかを確認する。 - すべての一覧をページ分割し、ページサイズの上限を設定する。
- ログインと負荷の高いルートにレート制限をかける。レート制限とはを参照。
- CORSは、他ドメインのブラウザがAPIを呼ぶ必要がある場合のみ設定し、許可するオリジンは明示的に列挙する。表示されるエラーについては、CORSエラーの直し方で解説しています。
- 各ルートのドキュメントとテストを書く。失敗するケースも含める。
- デプロイする:秘密情報は環境変数に、HTTPS、ログ、ヘルスチェックを設定する。
AIビルダーへのプロンプト
構築:
予約用のREST APIを作成してください。ルートは次のとおりです:GET /api/health、GET /api/bookings(ページ分割、1ページ最大50件)、POST /api/bookings、GET /api/bookings/:id、PATCH /api/bookings/:id、DELETE /api/bookings/:id。データはうちのデータベースに保存してください。リクエストボディはスキーマライブラリで検証し、未知のフィールドは拒否してください。エラーは {"error": {"code", "message"}} の形式でJSONを返し、正しいステータスコード(400、401、403、404、409)を使ってください。秘密情報は環境変数に保存してください。
セキュリティ:
予約関連のすべてのルートでログインを必須にしてください。読み取り、更新、削除のたびに、予約が現在のユーザーのものかをサーバー側で確認し、違う場合は404を返してください。リクエストボディからユーザーIDやロールを受け取らないでください。POST /api/bookings はユーザーごとに毎分20回までに制限してください。エラーはサーバー側でログに残し、スタックトレースは返さないでください。
ドキュメント:
これらのルートのOpenAPI記述と、各ルートのリクエスト・レスポンス例を含む短いREADMEを書いてください。
APIをテストする
フロントエンドの外から、攻撃者と同じようにテストします。
- 各ルートが有効な入力で動作し、ドキュメントどおりの形式とコードを返す
- 必須項目が欠けている、または無効な入力は、分かりやすいメッセージとともに400を返す
- トークンなしで保護されたルートを呼ぶと、すべて401を返す
- ユーザーAがユーザーBのレコードをIDで要求すると、404または403になる
- 一覧はページ分割されており、大きすぎる
limitは上限に抑えられる - 重複や競合する作成は500ではなく409を返す
- レート制限に達すると429を返す
- エラーレスポンスにスタックトレース、SQL、秘密情報が含まれない
- CORSは意図したオリジンだけを許可する
よくあるミス
- ログインは確認するが、所有者は確認しない。 APIで最も多い穴です。ログイン中の任意のユーザーが、IDを変えるだけで任意のレコードを読めてしまいます。
- クライアントを信用する。 リクエストボディの価格、ロール、ユーザーIDは編集されてしまう可能性があります。
- データベースの行をそのまま返す。 パスワードのハッシュや内部フィールドが漏れます。各レスポンスに含める項目を選んでください。
- 上限のない一覧。 すべてのレコードを一度に返すと、アプリ全体が遅くなります。
- エラーを含んだ
200 OK。 クライアントも監視も失敗を検知できません。 - Cookieを使うAPIで、CORSをすべて許可する。
- ヘルスチェックもログもない。 障害をユーザーからの連絡で知ることになります。
公開前の全体的な確認については、AIで作ったアプリのセキュリティチェックリストを参照してください。
Mythexで REST APIを作る
アプリの一部として、または独立したサービスとして、Mythexに API を依頼できます。ドキュメントのREST APIバックエンドのレシピには開始用のプロンプトがあります。フレームワークとルートを指定し、分かりやすいJSONエラーを求め、秘密情報は環境変数に保持し、Dockerfileを含めるように依頼します。Node、Python、C#、Javaなどのコンテナバックエンドは Dockerfile を通じて公開され、Mythexは公開画面からデプロイを処理します(APIバックエンド)。プロジェクトではWebサイトとAPIサーバーを並行して動かすことができ、プレビューで切り替えられます。秘密情報はプロジェクトのシークレットとして保存し、APIにデータベースが必要ならチャットで依頼してください。APIと組み合わせる定期処理については、バックグラウンドジョブの実行方法を参照してください。
よくある質問
REST APIとは何ですか?
REST APIは、プログラムがHTTP経由でアプリのデータを扱うための方法です。データの種類ごとに独自のURL(例:/orders)を持つリソースがあり、標準的なメソッドで操作します。読み取りはGET、作成はPOST、更新はPATCHまたはPUT、削除はDELETEです。データは通常JSON形式で送ります。
REST APIはどの言語で作るべきですか?
自分やチームが保守できるものを使ってください。ExpressまたはFastifyを使うNode.js、FastAPIを使うPython、C#やJavaのフレームワークはいずれも適しています。ルート、ステータスコード、検証、認証のルールの方が、言語選びより重要です。
REST APIのセキュリティはどう確保しますか?
公開されていないすべてのルートで認証を必須にし、呼び出し元が個々のレコードにアクセスできるかをサーバー側で確認し、すべての入力を検証し、HTTPSを使い、リクエストにレート制限をかけ、秘密情報は環境変数に保存してください。クライアントから送られたIDやロールは決して信用しないでください。
REST APIのために別のバックエンドは必要ですか?
必ずしも必要ではありません。Next.jsのようなフレームワークは、ページと並べてAPIルートを提供できます。Web、モバイル、パートナーなど複数のクライアントが利用する場合や、独自の言語やスケーリングが必要な場合に、別のAPIサービスを作る意味があります。