前提条件
- IaC は CDK(CDK v2)
- Lambda のランタイムは Node.js 18(拡張子は.mjs)
- Lambda の実装は TypeScript(AWS SDK for JavaScript v3)
ファイル 構成
cdk init
で自動生成される構成から多少変更している。
実践!AWS CDK #7 ファイル分割を参考に、AWS リソースごとにリソース定義ファイルを分割している。
Lambda のコンパイル用に別途tsconfig.json
を用意する。
├─ src/
│ ├─ lib/
│ │ ├─ api-gateway/
│ │ │ ├─ handlers/
│ │ │ │ └─ sample-api/
│ │ │ │ └─ index.ts // Lambdaコード
│ │ │ │
│ │ │ └─ resource.ts // API Gateway + API GatewayがトリガのLambda定義
│ │ │
│ │ ├─ sample-stack.ts
│ │ └─ tsconfig.json // Lambdaのコンパイルに使用するtsconfig
│ │
│ └─ main.ts
│
├─ .gitignore
├─ .npmignore
├─ cdk.json
├─ jest.config.js
├─ package.json
├─ package-lock.json
└─ tsconfig.json // CDKコンパイルに使用するtsconfig
実装
tsconfig.json
基本的にcdk init
で自動生成されたものそのまま
tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["es2020"],
"declaration": true,
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"noImplicitThis": true,
"alwaysStrict": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": false,
"inlineSourceMap": true,
"inlineSources": true,
"experimentalDecorators": true,
"strictPropertyInitialization": false,
"typeRoots": ["./node_modules/@types"],
"esModuleInterop": true
},
"exclude": ["node_modules", "cdk.out"]
}
src/lib/tsconfig.json
上記のtsconfig.json
をベースにするため、extends
で指定。
ts
をmjs
にコンパイルするため、module
にES2022
を指定。
src/lib/tsconfig.json
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true
}
}
src/main.ts
src/main.ts
import * as cdk from 'aws-cdk-lib';
import { SampleStack } from './lib/sample-stack';
const app = new cdk.App();
new SampleStack(app, 'SampleStack');
src/lib/sample-stack.ts
src/lib/sample-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { ApiGateway } from './api-gateway/resource';
export class SampleStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: cdk.StackProps) {
super(scope, id, props);
const environment = 'develop';
const apiGateway = new ApiGateway({
environment,
});
apiGateway.createResources(this);
}
}
src/lib/api-gateway/resource.ts
Lambda のランタイムに Node.js 18 を指定。
Lambda の bundling オプションtsconfig
でsrc/lib/tsconfig.json
を指定。
resource.ts
import * as path from 'path';
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
interface Parameters {
environment: string;
}
export class ApiGateway {
private _parameters: Parameters;
constructor(parameters: Parameters) {
this._parameters = parameters;
}
public createResources(scope: Construct) {
const runtime = cdk.aws_lambda.Runtime.NODEJS_18_X;
const bundling = {
minify: true,
sourceMap: true,
externalModules: ['@aws-sdk/*'],
tsconfig: path.join(__dirname, '../tsconfig.json'),
format: cdk.aws_lambda_nodejs.OutputFormat.ESM,
};
const lambdaBasicRole = new cdk.aws_iam.Role(scope, 'lambda-basic-role', {
assumedBy: new cdk.aws_iam.ServicePrincipal('lambda.amazonaws.com'),
managedPolicies: [cdk.aws_iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')],
});
const sampleFunction = new cdk.aws_lambda_nodejs.NodejsFunction(scope, 'sample-function', {
functionName: `${this._parameters.environment}_sampleFunction`,
entry: path.join(__dirname, './handlers/sample-api/index.ts'),
handler: 'handler',
runtime,
memorySize: 1024,
role: lambdaBasicRole,
bundling,
});
}
}
src/lib/api-gateway/handlers/sample-api/index.ts
src/lib/api-gateway/handlers/sample-api/index.ts
export const handler = async event => {
console.log(event.path);
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ type: 'sample' }),
};
};