Claude Code×AWS API Gateway実装ガイド:SAMでHTTP APIを作り認証・CORS・ログ・制限までレビューする
API GatewayをClaude Codeで設計・実装。HTTP API、SAM、CORS、ログ、認証、制限を実例で解説。
API Gatewayは「外に出すAPIの入口」
API Gatewayは、外部公開するAPIの入口で、認証・制限・ログ・バックエンド接続をまとめる層です。ブラウザやモバイルアプリから来たリクエストを受け、Lambda、HTTPサーバー、AWSサービスなどへ渡し、レスポンスを返します。初心者向けに言うなら「玄関、受付、警備、通行記録、奥の部屋への案内」を一か所に集めたものです。
MasaがAPI Gatewayで一番つまずいたのは、Lambdaのコードではありませんでした。CORSをどこで返すのか、JWT認証をAPI Gateway側で見るのかLambda側で見るのか、ログに何を出せば障害対応できるのか、スロットリングをどの値にするのか。この境界を曖昧にしたままClaude Codeへ「API作って」と頼むと、動くけれど本番運用に弱い構成が出ます。
この記事では、AWS公式ドキュメントを確認しながら、Claude CodeにレビューさせやすいAPI Gateway設計に直します。対象は最初の1本として使いやすいHTTP APIです。より高機能なREST API、双方向通信のWebSocket APIも比較し、Lambda連携、CORS、JWT/IAM認証、ステージログ、レート制限の実例を入れます。
公式情報から見る3種類のAPI
AWS公式の概念説明では、API GatewayはRESTful API、WebSocket API、HTTPやLambdaなどのバックエンド連携を管理するサービスです。API Gatewayには主にREST API、HTTP API、WebSocket APIがあります。
| 種類 | 向いている用途 | 迷った時の判断 |
|---|---|---|
| HTTP API | SPAやモバイルからLambda/HTTPへつなぐ一般的なJSON API | 低コスト、低レイテンシ、JWT認証、CORSが中心なら最初に選ぶ |
| REST API | APIキー、利用プラン、リクエスト検証、WAF、Private APIなど細かい管理が必要 | B2B API、顧客別レート制限、厳密なAPI管理が必要なら選ぶ |
| WebSocket API | チャット、通知、進捗配信など双方向通信 | クライアントへサーバーから押し返したいなら選ぶ |
AWSの比較表でも、REST APIは機能が多く、HTTP APIは必要最小限の機能で低価格に寄せた製品とされています。APIキーや顧客別スロットリング、リクエスト検証、AWS WAF、Private APIが必要ならREST API。JWT認証とLambda連携を早く公開したいならHTTP API、という切り分けが現実的です。
今回のサンプルはHTTP APIで作ります。理由は、Claude Codeと相性がよいからです。ルート、Lambda、CORS、ログ、制限の対応関係がテンプレートにまとまり、初学者でも差分レビューしやすいです。REST APIが悪いわけではなく、要件が増えた時の移行先として残しておくのが良いです。
公式リンク:
ユースケースを先に決める
API Gatewayの記事で薄くなりやすいのは、いきなりテンプレートを書くことです。先に「どの入口を守るのか」を決めると、Claude Codeの出力が急に現実的になります。
1つ目はLambda連携です。問い合わせフォーム、予約フォーム、社内ツールのWebhookなど、リクエストを受けて軽い検証をし、DBやメール送信に渡すAPIです。API Gatewayは公開URLとルーティングを担当し、Lambdaはビジネスロジックを担当します。
2つ目はCORSです。フロントエンドが https://example.com、APIが https://xxxx.execute-api.ap-northeast-1.amazonaws.com のように別オリジンになると、ブラウザは安全のために制限します。AWS公式では、HTTP APIでCORSを設定するとAPI GatewayがプリフライトOPTIONSへ応答し、統合先から返したCORSヘッダーを無視する場合があると説明されています。つまり「LambdaにもCORSを書いたから大丈夫」ではなく、API Gateway側の設定を本命にする必要があります。
3つ目はJWT/IAM認証です。ユーザー向けAPIならCognitoや外部IdPのJWTをHTTP APIのJWT authorizerで検証します。社内バッチや別AWSアカウントから叩くAPIならIAM認証にして、クライアントにSigV4署名を要求します。AWS公式では、HTTP APIのJWT authorizerはissuer、audience、期限、scopeなどを検証し、IAM認証では execute-api 権限を持つ署名付きリクエストだけを通します。
4つ目はステージ、ログ、レート制限です。CloudWatch Logsへアクセスログを残すと、requestId、routeKey、status、IP、時刻を追えます。スロットリングはトークンバケット方式で、超過時は 429 Too Many Requests になります。ただしAWS公式は、スロットリングやクォータは厳密な天井ではなく目標値として考えるべきだと説明しています。過信せず、バックエンド側の保護も合わせます。
コピーして動かすSAMサンプル
以下はAWS SAMでHTTP API、Lambda、CORS、アクセスログ、ステージ単位のスロットリングをまとめた最小構成です。JWT認証は後段で差し込めるよう、まずは公開APIとして動作確認し、Claude Codeに「公開ルートが残っていないか」をレビューさせます。
template.yaml を作成します。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Claude Code Lab HTTP API sample with CORS, logs, throttling, and Lambda proxy
Parameters:
StageName:
Type: String
Default: Prod
AllowedOrigin:
Type: String
Default: https://example.com
Globals:
Function:
Runtime: nodejs20.x
Architectures:
- arm64
Timeout: 10
MemorySize: 256
Resources:
ApiAccessLogs:
Type: AWS::Logs::LogGroup
Properties:
RetentionInDays: 14
PublicHttpApi:
Type: AWS::Serverless::HttpApi
Properties:
StageName: !Ref StageName
CorsConfiguration:
AllowOrigins:
- !Ref AllowedOrigin
AllowHeaders:
- authorization
- content-type
- x-request-id
AllowMethods:
- GET
- POST
- OPTIONS
MaxAge: 300
AccessLogSettings:
DestinationArn: !GetAtt ApiAccessLogs.Arn
Format: '{"requestId":"$context.requestId","routeKey":"$context.routeKey","status":"$context.status","ip":"$context.identity.sourceIp","requestTime":"$context.requestTime","responseLength":"$context.responseLength"}'
DefaultRouteSettings:
ThrottlingBurstLimit: 20
ThrottlingRateLimit: 10
RouteSettings:
"POST /contacts":
ThrottlingBurstLimit: 5
ThrottlingRateLimit: 2
FailOnWarnings: true
HealthFunction:
Type: AWS::Serverless::Function
Properties:
Handler: src/handler.health
Events:
Health:
Type: HttpApi
Properties:
ApiId: !Ref PublicHttpApi
Path: /health
Method: GET
PayloadFormatVersion: "2.0"
ContactFunction:
Type: AWS::Serverless::Function
Properties:
Handler: src/handler.contact
Events:
Contact:
Type: HttpApi
Properties:
ApiId: !Ref PublicHttpApi
Path: /contacts
Method: POST
PayloadFormatVersion: "2.0"
TimeoutInMillis: 10000
Outputs:
ApiUrl:
Description: Invoke URL
Value: !Sub "https://${PublicHttpApi}.execute-api.${AWS::Region}.${AWS::URLSuffix}/${StageName}/"
package.json を作成します。
{
"type": "module",
"scripts": {
"check": "node --check src/handler.js"
}
}
src/handler.js を作成します。
const json = (statusCode, body) => ({
statusCode,
headers: {
"content-type": "application/json"
},
body: JSON.stringify(body)
});
export const health = async () => {
return json(200, {
ok: true,
service: "claude-code-api-gateway",
checkedAt: new Date().toISOString()
});
};
export const contact = async (event) => {
let payload;
try {
payload = JSON.parse(event.body ?? "{}");
} catch {
return json(400, { message: "Request body must be valid JSON." });
}
const name = String(payload.name ?? "").trim();
const email = String(payload.email ?? "").trim();
if (!name || !email.includes("@")) {
return json(422, {
message: "name and a valid email are required.",
requestId: event.requestContext?.requestId
});
}
return json(202, {
message: "accepted",
requestId: event.requestContext?.requestId,
received: { name, email }
});
};
Git BashやmacOS/Linuxなら次で確認できます。
npm run check
sam build
sam deploy --guided \
--stack-name clc-api-gateway-sample \
--parameter-overrides AllowedOrigin=https://example.com
API_URL=$(aws cloudformation describe-stacks \
--stack-name clc-api-gateway-sample \
--query "Stacks[0].Outputs[?OutputKey=='ApiUrl'].OutputValue" \
--output text)
curl "${API_URL}health"
curl -X POST "${API_URL}contacts" \
-H "content-type: application/json" \
-d '{"name":"Masa","email":"masa@example.com"}'
Windows PowerShellならURL取得と疎通だけ次の形にします。
$apiUrl = aws cloudformation describe-stacks `
--stack-name clc-api-gateway-sample `
--query "Stacks[0].Outputs[?OutputKey=='ApiUrl'].OutputValue" `
--output text
curl.exe ($apiUrl + "health")
curl.exe -X POST ($apiUrl + "contacts") `
-H "content-type: application/json" `
-d "{\"name\":\"Masa\",\"email\":\"masa@example.com\"}"
認証は後付けではなくレビュー項目にする
サンプルはまず動作確認を優先して公開ルートにしています。本番ではここを放置してはいけません。API Gatewayの認証は、少なくとも次の3パターンで考えます。
JWT authorizerは、ログイン済みユーザーがブラウザやモバイルアプリから叩くAPI向けです。CognitoやOIDCプロバイダーが発行したアクセストークンをAPI Gatewayが検証し、scopeもルート単位で見られます。Lambda側で毎回JWTライブラリを呼ぶより、入口で拒否できるので責務が明確です。
IAM認証は、AWS上のワークロード同士、社内バッチ、管理ツール向けです。HTTP APIでもIAM authorizationを有効にでき、クライアントはSigV4で署名します。認証に失敗したリクエストはLambdaまで届きません。
Lambda authorizerは、独自ルールが必要な時の逃げ道です。既存の会員DB、IP制限、取引先別契約、複雑な権限判定があるなら使います。ただしauthorizer自体の遅延、キャッシュ、障害時の影響も設計対象に入ります。
Claude Codeには次のようにレビューさせます。
このAWS SAMテンプレートのAPI Gateway設定を本番前レビューしてください。
観点:
- 認証なしで公開されているルートがないか
- CORSのAllowOriginsが広すぎないか
- JWT/IAM/Lambda authorizerのどれを選ぶべきか
- AccessLogSettingsに障害対応に必要なrequestId, routeKey, statusが入っているか
- ThrottlingBurstLimitとThrottlingRateLimitが問い合わせフォーム用途として妥当か
- Lambda側に入力検証、タイムアウト、エラーレスポンスがあるか
- REST APIを選ぶべき要件、例えばAPIキーや顧客別利用プランがないか
修正案は差分で出してください。
このプロンプトの良いところは、Claude Codeに「コードを書いて」ではなく「本番事故を探して」と依頼している点です。API Gatewayは入口なので、機能追加より先に穴をふさぐレビューが効きます。
失敗例と落とし穴
失敗例1は、CORSをLambdaだけで返すことです。HTTP APIでCORSを設定している場合、API Gateway側がプリフライト応答やヘッダー付与を担当します。Lambdaのレスポンスに access-control-allow-origin を書いても、期待通りにならないケースがあります。CORSはフロントエンドURL、Cookie利用有無、Authorizationヘッダーの有無とセットで設計します。
失敗例2は、ログを後回しにすることです。LambdaのCloudWatch Logsだけでは、API Gatewayが返した 403、404、429、統合前のエラーを追いにくいです。アクセスログに requestId と routeKey を入れると、問い合わせや監視アラートから該当ルートへ戻れます。個人情報やAuthorizationヘッダーをログに出さないことも忘れてはいけません。
失敗例3は、スロットリングを「絶対に超えない上限」と思い込むことです。AWS公式はベストエフォートの目標値として説明しています。大量アクセス時に守るべき順番は、API Gatewayの制限、Lambdaの同時実行数、DBや外部APIの制限、クライアント側のリトライ制御です。429 を受けたクライアントは指数バックオフする前提にします。
失敗例4は、HTTP APIで足りるのにREST APIから始めること、またはREST APIが必要なのにHTTP APIで押し切ることです。APIキー、顧客別利用プラン、リクエスト検証、WAF、Private APIが要件にあるならREST APIを検討します。単純なLambda公開、JWT、CORS、ログならHTTP APIで十分なことが多いです。
Claude Codeで設計品質を上げる流れ
私なら、Claude Codeへ一度に全部作らせません。まずAPIの責務を箇条書きにし、HTTP APIで足りるか、REST APIにすべきかを比較させます。次にSAMテンプレートだけを生成させ、最後にLambdaコードとエラー応答を足します。この順番にすると、CORSや認証が「後で入れるもの」になりにくいです。
おすすめの作業単位は、1回目がルート設計、2回目がSAM、3回目が認証、4回目がログとスロットリング、5回目が運用レビューです。Claude Codeのコンテキストが汚れたら、テンプレートとレビュー結果だけを残して新しいセッションに渡します。このやり方は、API Gatewayのような設定項目が多いAWSサービスで特に効きます。
関連して読むなら、Lambda側の責務は Claude Code AWS Lambda完全ガイド に分け、ログ設計は Claude Code AWS CloudWatch活用、権限設計は Claude Code AWS IAMガイド と合わせて読むと理解しやすいです。
研修・教材CTA
Claude CodeでAWS構成を作る時に大事なのは、プロンプトの上手さだけではありません。レビュー観点、公式ドキュメントの読み方、IAMとログの境界、失敗時に戻れるチェックリストが必要です。ClaudeCodeLabでは、こうした実務向けのClaude Code活用を 研修・教材ページ に整理しています。
特にAPI Gatewayは、記事を読むだけだと「なんとなく設定できた」で止まりやすい領域です。自社のAPI、問い合わせフォーム、管理画面、外部連携Webhookに合わせてレビュー観点を作ると、Claude Codeがかなり頼れる相棒になります。
Masaの手元で試した結果
Masaの手元では、上の構成をベースに node --check でLambdaハンドラの構文を確認し、SAMテンプレートではCORS、アクセスログ、ルート別スロットリングをClaude Codeにレビューさせました。特に効果があったのは、ログ形式に requestId と routeKey を必ず入れる指摘、POST /contacts だけ制限を強める設計、公開ルートを後で認証付きへ変える作業を別チケット化する流れです。以前のようにLambdaコードから作り始めるより、レビューで見つかる漏れが明らかに減りました。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
ObsidianメモをCLAUDE.mdに変えるClaude Code運用: 文脈を毎回説明しない仕組み
Obsidianの作業メモからCLAUDE.md用の運用ノートを作り、Claude Codeに安定した文脈を渡す方法。
Claude Code Revenue CTA Routing: 記事からPDF、Gumroad、相談へ送る設計
PVだけで終わらせず、読者の状態に合わせて無料PDF、Gumroad教材、導入相談へ分岐するCTA設計です。
Claude Codeチーム引き継ぎルール: レビュー、権限、収益導線まで渡す実務手順
Claude Codeの作業をチームで渡すための証拠、権限、ロールバック、無料PDF/Gumroad/相談導線の実務ルール。