😺

APIGateaway + LambdaをCDKで作成

2024/10/06に公開

cdkにてAPIGateway + Lambdaの作成方法についてのまとめ
ServerlessFWがV4から有料になったのでcdkで構築する

typescriptを用いて構築します。

aws cdkはインストール済みとします

プロジェクトの初期化

新しいCDKプロジェクトの初期化

mkdir my-api-lambda
cd my-api-lambda
cdk init app --language typescript

cdk init app --language typescriptを実行するとTypeScript用のプロジェクトが作成されます。
下記が作成された中身の例です

my-api-lambda/
├── bin/
│   └── my-api-lambda.ts
├── lib/
│   └── my-api-lambda-stack.ts
├── test/
│   └── my-api-lambda.test.ts
├── 省略
  • bin: エントリーポイントとなる実行ファイルを格納
    • my-api-lambda.ts: 実際に実行するlambdaファイル
    • 複数lambdaを作成する場合こちらに新規でディレクトリ・ファイルの追加することも可能
  • lib: CDKスタックの定義ファイルを格納
    • my-api-lambda-stack.ts: インフラストラクチャを定義する主要なスタックファイル
    • LambdaやAPIGatewayの設定を記述

Lambdaの作成

bin/my-api-lambda.tsの中に実際の処理を作成していきます。
複数のlambdaを作成する場合、ディレクトリを作成してその中にlambda実行ファイルを作成することも可能です。

1番簡単な例として、APIがリクエストされたら「Hello World」を返すLambdaです。

// bin/my-api-lambda.ts
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';

export async function handler(event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> {
  return {
    statusCode: 200,
    body: JSON.stringify({ message: "Hello World!" }),
  };
}

aws-lambdaの部分は下記でインストールできます。

npm install --save-dev @types/aws-lambda

クエリパラメータ

APIのリクエストでクエリパラメータを使用する場合
下記の方法で取得できます。

const queryParams = event.queryStringParameters


URL: https://api.example.com/resource?name=John&age=30
結果: { name: 'John', age: '30' }

パスパラメータ

パスパラメータを使用して値を受け取る場合

const pathParams = event.pathParameters;


/users/{userId}の場合
URL: https://api.example.com/users/123
結果: { userId: '123' }

リクエストボディの取得

POSTでリクエストボディを受け取る場合

const requestBody = event.body ? JSON.parse(event.body) : null;


リクエストボディ: { "title": "例", "content": "ポストの例" }
結果

{
  "title": "例",
  "content": "ポストの例"
}

スタックの作成

lib/my-api-lambda-stack.tsにあるファイルを修正して、先程作成したLambdaと呼び出すためのAPIGatewayを定義していきます。
@aws-cdk/aws-lambda-nodejsを使用することでTypeScriptコードを自動的にバンドル・コンパイルしてくれます。

npm install @aws-cdk/aws-lambda-nodejs esbuild

Lambdaの作成

const myLambda = new lambdaNodejs.NodejsFunction(this, 'MyLambdaHandler', {
      runtime: lambda.Runtime.NODEJS_20_X,
      entry: 'bin/my-api-lambda.ts',
      handler: 'handler',
      environment: {
          MY_VARIABLE: '123',
      }
    });

new lambdaNodejs.NodejsFunction: Lambdaの作成をおこなう
runtime: Lambda関数の実行環境を指定
entry: TypeScriptのエントリーポイント
handler: エクスポートされた関数名
environment: 環境変数の設定

Lambdaが複数ある場合は1つずつ作成する必要があります。
entryだけ異なる場合は関数化してファイルパスを引数で渡すだけで作成できるようにすると便利です。

APIGatewayの作成

const api = new apigateway.RestApi(this, 'MyApi', {
      restApiName: 'My Service',
      description: 'This is my API service.',
});

new apigateway.RestApi: Apiの作成
restApiName: API名

エンドポイントとメソッドの追加

/usersでアクセスしたい場合

// apiに追加
const users = api.root.addResource('users');

GETでリクエストする場合

users.addMethod('GET');

/users/{userId}でパスパラメータの追加

// usersにaddResourceで追加
const user = users.addResource('{userId}');
user.addMethod('POST')

独自ドメインの追加

APIGatewatに独自ドメインを追加する場合
証明書のArnを取得して設定をおこなう

// 証明書の取得
const certificateArn = '証明書のarnを設定';
const certificate = certificatemanager.Certificate.fromCertificateArn(this, 'Certificate', certificateArn);

// 独自ドメインの追加
api.addDomainName('CustomDomain', {
  domainName: 'api.example.com',
  certificate: certificate,
});

ステージの設定

デフォルトのステージは/prodですが変更することが可能

const api = new apigateway.RestApi(this, 'MyApi', {
      restApiName: 'My Service',
      description: 'This is my API service.',
      deployOptions: {
        stageName: 'dev'
      }
});

deployOptionsstageNameに設定することで/prodeではなく、/devに変更可能

実際のStack

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
mport * as lambdaNodejs from 'aws-cdk-lib/aws-lambda-nodejs';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';

export class MyApiLambdaStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Lambda関数を作成
    const myLambda = new lambdaNodejs.NodejsFunction(this, 'MyLambdaHandler', {
      runtime: lambda.Runtime.NODEJS_20_X,
      entry: 'bin/my-api-lambda.ts',
      handler: 'handler.handler',
    });

    // API Gatewayを作成
    const api = new apigateway.RestApi(this, 'MyApi');

    // リソースとメソッドを設定
    const users = api.root.addResource('users');
    const user = users.addResource('{userId}');
    user.addMethod('GET', new apigateway.LambdaIntegration(myLambda));
    user.addMethod('POST', new apigateway.LambdaIntegration(myLambda));
  }
}

その他

APIGateway+Lambdaをcdkで作成する方法です。
実際は特定のVPC内に設置や、特定のアカウントからのみアクセス可能などセキュリティ周りの設定が追加になるかもです。

Discussion