3
3

More than 1 year has passed since last update.

AWS CDK - Node.js 18 TypeScript での Lambda 実装

Last updated at Posted at 2022-12-30

前提条件

  • 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で指定。
tsmjsにコンパイルするため、moduleES2022を指定。

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 オプションtsconfigsrc/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' }),
  };
};

参考

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3