取り組みの背景 — なぜ Antigravity × AWS Lambda なのか
サーバーレスアーキテクチャは、インフラ管理の負担を大幅に軽減しながらスケーラブルなAPIを構築できる手法として、多くの開発者に支持されています。中でも AWS Lambda は、イベント駆動型の関数実行基盤として業界標準の地位を確立しました。
しかし、Lambda 関数の作成・API Gateway の設定・DynamoDB テーブルの定義・IAMポリシーの構成など、AWS サーバーレス開発には多くの設定作業が伴います。ここで Antigravity のAIエージェントが力を発揮します。エージェントに指示を出すだけで、ボイラープレートコードの生成からインフラ定義まで一貫して自動化できるのです。
ここではAntigravity を使って AWS Lambda 上にサーバーレスREST APIを構築する手順を、実際のコード例とともにステップバイステップで解説します。DynamoDB によるデータ永続化、API Gateway によるエンドポイント公開、S3 によるファイルストレージ連携まで、実用的なサーバーレスバックエンドの構築方法を学べます。
この記事の対象読者:
- AWS の基本的なサービス(Lambda, DynamoDB, S3)を聞いたことがある方
- Antigravity でバックエンド開発を効率化したい方
- サーバーレスアーキテクチャに興味がある中級開発者
前提環境の準備
Antigravity でAWSサーバーレス開発を始めるには、いくつかのツールを事前にセットアップしておく必要があります。
必須ツール:
- Antigravity(最新版推奨)
- AWS CLI v2(
aws configureで認証済み) - Node.js 20 LTS 以上
- AWS SAM CLI または Serverless Framework
Antigravity のターミナルで以下のコマンドを実行し、環境を確認しましょう。
# AWS CLI の認証状態を確認
aws sts get-caller-identity
# 出力例:
# {
# "UserId": "AIDACKCEVSQ6C2EXAMPLE",
# "Account": "123456789012",
# "Arn": "arn:aws:iam::123456789012:user/dev-user"
# }
# SAM CLI のバージョンを確認
sam --version
# SAM CLI, version 1.120.0AWS CLIの認証が完了していない場合は、aws configure コマンドでアクセスキーとリージョンを設定してください。ここでは ap-northeast-1(東京リージョン)を使用します。
プロジェクトの初期化 — Antigravity でスキャフォールド
まずは Antigravity のエージェントにプロジェクトの雛形を生成させます。エージェントチャットで以下のように指示します。
AWS SAM を使って、DynamoDB をデータストアとする
REST API プロジェクトを初期化してください。
ランタイムは Node.js 20、TypeScript で構築します。
エンドポイントは CRUD 操作(GET/POST/PUT/DELETE)を用意してください。
Antigravity のエージェントが template.yaml(SAM テンプレート)と Lambda 関数のコードを自動生成します。生成されたプロジェクト構造を確認しましょう。
serverless-api/
├── template.yaml # SAM テンプレート(インフラ定義)
├── src/
│ ├── handlers/
│ │ ├── createItem.ts # POST /items
│ │ ├── getItem.ts # GET /items/{id}
│ │ ├── listItems.ts # GET /items
│ │ ├── updateItem.ts # PUT /items/{id}
│ │ └── deleteItem.ts # DELETE /items/{id}
│ ├── lib/
│ │ ├── dynamodb.ts # DynamoDB クライアントヘルパー
│ │ └── response.ts # API レスポンスユーティリティ
│ └── types/
│ └── item.ts # 型定義
├── tsconfig.json
├── package.json
└── samconfig.toml
SAM テンプレートの構成 — インフラをコードで定義する
template.yaml は AWS のインフラをコードとして定義するファイルです。Antigravity が生成したテンプレートのポイントを見ていきましょう。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Serverless REST API with DynamoDB
Globals:
Function:
Timeout: 15
Runtime: nodejs20.x
MemorySize: 256
Environment:
Variables:
TABLE_NAME: !Ref ItemsTable
BUCKET_NAME: !Ref AssetsBucket
Resources:
# API Gateway
ApiGateway:
Type: AWS::Serverless::Api
Properties:
StageName: prod
Cors:
AllowMethods: "'GET,POST,PUT,DELETE,OPTIONS'"
AllowHeaders: "'Content-Type,Authorization'"
AllowOrigin: "'*'"
# DynamoDB テーブル
ItemsTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: serverless-items
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
# S3 バケット(ファイルアップロード用)
AssetsBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "${AWS::StackName}-assets"
CorsConfiguration:
CorsRules:
- AllowedMethods: [GET, PUT]
AllowedOrigins: ['*']
AllowedHeaders: ['*']
# Lambda 関数(Create)
CreateItemFunction:
Type: AWS::Serverless::Function
Properties:
Handler: src/handlers/createItem.handler
Events:
CreateItem:
Type: Api
Properties:
RestApiId: !Ref ApiGateway
Path: /items
Method: post
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref ItemsTable
# Lambda 関数(List)
ListItemsFunction:
Type: AWS::Serverless::Function
Properties:
Handler: src/handlers/listItems.handler
Events:
ListItems:
Type: Api
Properties:
RestApiId: !Ref ApiGateway
Path: /items
Method: get
Policies:
- DynamoDBReadPolicy:
TableName: !Ref ItemsTableここでのポイントは、DynamoDB の BillingMode: PAY_PER_REQUEST(オンデマンド課金)を選択している点です。開発初期やトラフィックが予測しにくいプロジェクトでは、プロビジョニングモードよりもコスト効率が良くなります。
Lambda 関数の実装 — TypeScript で型安全に
次に、Lambda 関数の具体的な実装を見ていきます。まずはDynamoDB クライアントのヘルパーモジュールから始めます。
// src/lib/dynamodb.ts
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import {
DynamoDBDocumentClient,
PutCommand,
GetCommand,
ScanCommand,
UpdateCommand,
DeleteCommand,
} from "@aws-sdk/lib-dynamodb";
// DynamoDB Document Client を初期化
const client = new DynamoDBClient({ region: "ap-northeast-1" });
const docClient = DynamoDBDocumentClient.from(client);
const TABLE_NAME = process.env.TABLE_NAME || "serverless-items";
// アイテムを作成
export async function createItem(item: Record<string, unknown>) {
await docClient.send(
new PutCommand({
TableName: TABLE_NAME,
Item: item,
})
);
return item;
}
// IDでアイテムを取得
export async function getItemById(id: string) {
const result = await docClient.send(
new GetCommand({
TableName: TABLE_NAME,
Key: { id },
})
);
return result.Item;
}
// 全アイテムを取得(ページネーション対応)
export async function listAllItems(limit = 20, lastKey?: string) {
const params: Record<string, unknown> = {
TableName: TABLE_NAME,
Limit: limit,
};
if (lastKey) {
params.ExclusiveStartKey = { id: lastKey };
}
const result = await docClient.send(new ScanCommand(params));
return {
items: result.Items || [],
nextKey: result.LastEvaluatedKey?.id,
};
}
// アイテムを削除
export async function deleteItemById(id: string) {
await docClient.send(
new DeleteCommand({
TableName: TABLE_NAME,
Key: { id },
})
);
}続いて、POST エンドポイントの Lambda ハンドラーを実装します。
// src/handlers/createItem.ts
import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda";
import { randomUUID } from "crypto";
import { createItem } from "../lib/dynamodb";
import { success, error } from "../lib/response";
export async function handler(
event: APIGatewayProxyEvent
): Promise<APIGatewayProxyResult> {
try {
// リクエストボディをパース
const body = JSON.parse(event.body || "{}");
// バリデーション
if (!body.name || !body.description) {
return error(400, "name と description は必須です");
}
// アイテムを作成
const item = {
id: randomUUID(),
name: body.name,
description: body.description,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
const created = await createItem(item);
// 201 Created で返却
return success(201, created);
} catch (err) {
console.error("CreateItem error:", err);
return error(500, "アイテムの作成に失敗しました");
}
}レスポンスユーティリティも Antigravity に生成させます。CORS ヘッダーの設定漏れは頻出バグなので、ここで一元管理するのがポイントです。
// src/lib/response.ts
const headers = {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET,POST,PUT,DELETE,OPTIONS",
};
export function success(statusCode: number, body: unknown) {
return {
statusCode,
headers,
body: JSON.stringify(body),
};
}
export function error(statusCode: number, message: string) {
return {
statusCode,
headers,
body: JSON.stringify({ error: message }),
};
}S3 連携 — 署名付きURLでファイルアップロード
サーバーレスAPIでファイルアップロードを実装する場合、Lambda を経由せずに S3 の署名付きURL(Presigned URL)を活用するのがベストプラクティスです。Lambda のペイロード制限(6MB)を回避でき、大容量ファイルも効率的に扱えます。
// src/handlers/getUploadUrl.ts
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda";
import { randomUUID } from "crypto";
import { success, error } from "../lib/response";
const s3 = new S3Client({ region: "ap-northeast-1" });
const BUCKET = process.env.BUCKET_NAME!;
export async function handler(
event: APIGatewayProxyEvent
): Promise<APIGatewayProxyResult> {
try {
const body = JSON.parse(event.body || "{}");
const contentType = body.contentType || "application/octet-stream";
const key = `uploads/${randomUUID()}`;
// 署名付きURLを生成(有効期限: 15分)
const command = new PutObjectCommand({
Bucket: BUCKET,
Key: key,
ContentType: contentType,
});
const uploadUrl = await getSignedUrl(s3, command, { expiresIn: 900 });
return success(200, {
uploadUrl, // クライアントはこのURLにPUTでアップロード
key, // アップロード後のオブジェクトキー
expiresIn: 900,
});
} catch (err) {
console.error("GetUploadUrl error:", err);
return error(500, "アップロードURLの生成に失敗しました");
}
}クライアント側からは、取得した uploadUrl に対して PUT リクエストでファイルを直接アップロードします。
// クライアント側の実装例
async function uploadFile(file: File) {
// 1. 署名付きURLを取得
const res = await fetch("/items/upload-url", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ contentType: file.type }),
});
const { uploadUrl, key } = await res.json();
// 2. S3 に直接アップロード
await fetch(uploadUrl, {
method: "PUT",
headers: { "Content-Type": file.type },
body: file,
});
return key; // DynamoDB のレコードに紐づけて保存
}ローカル開発とデバッグ — SAM CLI でテスト
デプロイ前にローカルでAPIを動作確認するのは、サーバーレス開発の基本です。AWS SAM CLI を使えば、Lambda 関数をローカルで実行できます。
# ローカルで API Gateway + Lambda を起動
sam local start-api --warm-containers EAGER
# 出力例:
# Mounting CreateItemFunction at http://127.0.0.1:3000/items [POST]
# Mounting ListItemsFunction at http://127.0.0.1:3000/items [GET]
# ...
# 別ターミナルからテストリクエストを送信
curl -X POST http://127.0.0.1:3000/items \
-H "Content-Type: application/json" \
-d '{"name": "テストアイテム", "description": "SAM ローカルテスト"}'
# 期待する出力:
# {
# "id": "a1b2c3d4-...",
# "name": "テストアイテム",
# "description": "SAM ローカルテスト",
# "createdAt": "2026-03-28T12:00:00.000Z",
# "updatedAt": "2026-03-28T12:00:00.000Z"
# }Antigravity のエージェントにデバッグを依頼することもできます。「Lambda 関数の createItem が 500 エラーを返す。DynamoDB との接続を確認して」と伝えれば、エージェントがログを解析し、IAM ポリシーの不足や環境変数の設定漏れを特定してくれます。
デプロイと本番運用のベストプラクティス
ローカルテストが完了したら、実際に AWS にデプロイします。
# 初回デプロイ(ガイド付き)
sam deploy --guided
# 2回目以降
sam deploy
# デプロイ完了後、エンドポイントURLが表示される
# Outputs:
# ApiUrl: https://abc123.execute-api.ap-northeast-1.amazonaws.com/prod本番運用で押さえておくべきポイントをいくつか紹介します。
コールドスタート対策: Lambda 関数は一定時間アクセスがないとコンテナが破棄され、次回起動時に遅延(コールドスタート)が発生します。レイテンシが重要なAPIでは Provisioned Concurrency を設定するか、関数の初期化コードを最小限に抑えましょう。
# template.yaml でのProvisioned Concurrency設定
CreateItemFunction:
Type: AWS::Serverless::Function
Properties:
# ... 既存の設定
ProvisionedConcurrencyConfig:
ProvisionedConcurrentExecutions: 5モニタリング: CloudWatch Logs は自動的に有効になりますが、構造化ログを出力するとデバッグが格段に楽になります。Antigravity に「Lambda 関数に構造化ログ(JSON形式)を追加して」と指示すれば、@aws-lambda-powertools/logger を使ったログ実装を生成してくれます。
セキュリティ: IAM ポリシーは最小権限の原則に従い、各 Lambda 関数に必要最小限の権限のみ付与します。SAM テンプレートの Policies セクションで DynamoDBCrudPolicy や S3ReadPolicy など、SAM のポリシーテンプレートを活用するのが安全です。
さらに詳しいセキュリティパターンについては、Antigravity エージェントでセキュアな API バックエンドを構築する実践ガイド で認証・バリデーション・レート制限の実装を詳しく解説しています。
まとめ
Antigravity × AWS Lambda の組み合わせは、サーバーレスAPIの開発速度を大幅に向上させます。SAM テンプレートの生成、Lambda 関数の TypeScript 実装、DynamoDB ヘルパーの作成、S3 署名付きURLの実装まで、AIエージェントが一貫してサポートしてくれるため、AWSの設定作業に時間を取られることなく、ビジネスロジックの実装に集中できます。
サーバーレスアーキテクチャの次のステップとして、イベント駆動型のマイクロサービスに発展させたい方には、Antigravity × Event-Driven Architecture 実践ガイド も参考になるでしょう。