AWS Lambdaとは
AWS Lambdaは、サーバー管理なしでコードを実行できるサーバーレスコンピューティングサービスです。リクエスト数と実行時間に基づく従量課金制です。
セットアップ
AWS SAM CLI
# SAM CLIインストール
brew install aws-sam-cli
# プロジェクト初期化
sam init --runtime nodejs20.x --name my-lambda
# ディレクトリ構造
my-lambda/
├── template.yaml
├── src/
│ └── handlers/
│ └── hello.ts
├── package.json
└── tsconfig.json
template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
Timeout: 30
Runtime: nodejs20.x
MemorySize: 256
Environment:
Variables:
NODE_ENV: production
Resources:
HelloFunction:
Type: AWS::Serverless::Function
Properties:
Handler: dist/handlers/hello.handler
Events:
Api:
Type: Api
Properties:
Path: /hello
Method: get
Metadata:
BuildMethod: esbuild
BuildProperties:
Minify: true
Target: es2020
基本的なハンドラー
// src/handlers/hello.ts
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
export const handler = async (
event: APIGatewayProxyEvent
): Promise<APIGatewayProxyResult> => {
try {
const name = event.queryStringParameters?.name || 'World';
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
message: `Hello, ${name}!`,
timestamp: new Date().toISOString(),
}),
};
} catch (error) {
console.error('Error:', error);
return {
statusCode: 500,
body: JSON.stringify({ error: 'Internal Server Error' }),
};
}
};
DynamoDB連携
// src/handlers/users.ts
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import {
DynamoDBDocumentClient,
GetCommand,
PutCommand,
QueryCommand,
} from '@aws-sdk/lib-dynamodb';
const client = new DynamoDBClient({});
const docClient = DynamoDBDocumentClient.from(client);
const TABLE_NAME = process.env.USERS_TABLE!;
// ユーザー取得
export const getUser = async (event: APIGatewayProxyEvent) => {
const userId = event.pathParameters?.id;
const { Item } = await docClient.send(new GetCommand({
TableName: TABLE_NAME,
Key: { userId },
}));
if (!Item) {
return { statusCode: 404, body: JSON.stringify({ error: 'Not found' }) };
}
return { statusCode: 200, body: JSON.stringify(Item) };
};
// ユーザー作成
export const createUser = async (event: APIGatewayProxyEvent) => {
const body = JSON.parse(event.body || '{}');
const userId = crypto.randomUUID();
await docClient.send(new PutCommand({
TableName: TABLE_NAME,
Item: {
userId,
...body,
createdAt: new Date().toISOString(),
},
}));
return {
statusCode: 201,
body: JSON.stringify({ userId }),
};
};
template.yaml (DynamoDB)
Resources:
UsersTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: users
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: userId
AttributeType: S
KeySchema:
- AttributeName: userId
KeyType: HASH
UsersFunction:
Type: AWS::Serverless::Function
Properties:
Handler: dist/handlers/users.getUser
Environment:
Variables:
USERS_TABLE: !Ref UsersTable
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref UsersTable
ミドルウェアパターン(middy)
// src/handlers/protected.ts
import middy from '@middy/core';
import httpJsonBodyParser from '@middy/http-json-body-parser';
import httpErrorHandler from '@middy/http-error-handler';
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
const baseHandler = async (
event: APIGatewayProxyEvent & { body: any }
): Promise<APIGatewayProxyResult> => {
const { name, email } = event.body;
// ビジネスロジック
const result = await processUser({ name, email });
return {
statusCode: 200,
body: JSON.stringify(result),
};
};
// ミドルウェアをチェーン
export const handler = middy(baseHandler)
.use(httpJsonBodyParser())
.use(httpErrorHandler());
認証(Cognito連携)
// src/middleware/auth.ts
import { CognitoJwtVerifier } from 'aws-jwt-verify';
const verifier = CognitoJwtVerifier.create({
userPoolId: process.env.USER_POOL_ID!,
tokenUse: 'access',
clientId: process.env.CLIENT_ID!,
});
export const authMiddleware = () => ({
before: async (request: any) => {
const token = request.event.headers.authorization?.replace('Bearer ', '');
if (!token) {
throw { statusCode: 401, message: 'Unauthorized' };
}
try {
const payload = await verifier.verify(token);
request.event.user = payload;
} catch (error) {
throw { statusCode: 401, message: 'Invalid token' };
}
},
});
// 使用
export const handler = middy(baseHandler)
.use(authMiddleware())
.use(httpErrorHandler());
コールドスタート対策
// 接続の再利用
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
// ハンドラーの外で初期化(再利用される)
const client = new DynamoDBClient({});
export const handler = async (event) => {
// clientは再利用される
// ...
};
# Provisioned Concurrency(コールドスタート回避)
Resources:
MyFunction:
Type: AWS::Serverless::Function
Properties:
AutoPublishAlias: live
ProvisionedConcurrencyConfig:
ProvisionedConcurrentExecutions: 5
デプロイ
# ビルド
sam build
# ローカルテスト
sam local invoke HelloFunction --event events/hello.json
sam local start-api
# デプロイ
sam deploy --guided
# CI/CDでのデプロイ
sam deploy \
--stack-name my-app-prod \
--s3-bucket my-deploy-bucket \
--capabilities CAPABILITY_IAM \
--no-confirm-changeset
関連記事
- サーバーレスアーキテクチャ - 設計原則
- API Gateway - API管理
- AWS S3実践 - ストレージ連携
まとめ
AWS Lambdaは、スケーラブルなサーバーレスアプリケーションを構築できます。DynamoDB、API Gateway、Cognitoと組み合わせることで、フルスタックアプリを実現できます。
← Back to list