Serverless Express + AWS Lambda + API Gateway の構成を AWS CDK で作成してみた

2024.02.09

こんにちは、CX 事業本部製造ビジネステクノロジー部の若槻です。

Serverless Express は、AWS Lambda などのサーバーレス環境で Express.js を利用した REST API を構築できるライブラリです。

今回は、Serverless Express + AWS Lambda + API Gateway の構成を AWS CDK でデプロイして作成してみました。

試してみた

パッケージの導入

いくつかのパッケージ npm からインストールして導入します。

Serverless Express

@codegenie/serverless-express をインストールします。

npm i @codegenie/serverless-express

最近、Serverless Express が CodeGenie に移行したので、古い方のパッケージをインストールしないように注意してください。

その他

express および cors(必要な場合)をインストールします。

npm i express

npm i cors
npm i -D @types/cors

Lambda コード

Lambda ハンドラーのコードです。/companies パスへの POST メソッドのリクエストのルーティングを設定しています。

src/rest-api-router.ts

import serverlessExpress from '@codegenie/serverless-express';
import cors from 'cors';
import express, { Request, Response } from 'express';

const app = express();
app.use(cors());
app.use(express.json());

app.post('/companies', async (req: Request, res: Response): Promise<void> => {
  res.status(201).send({ ...req.body, id: 'c123' });
});

export const handler = serverlessExpress({ app });

CDK コード

AWS Lambda と API Gateway を作成する CDK スタックのコードです。LambdaRestApi コンストラクトクラスを使用することにより、Lambda プロキシ統合の REST API を作成できます。

lib/cdk-sample-stack.ts

import {
  aws_lambda,
  aws_lambda_nodejs,
  aws_apigateway,
  Stack,
  Duration,
  CfnOutput,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class CdkSampleStack extends Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    /**
     * Lambda 関数を作成
     */
    const restApiFunc = new aws_lambda_nodejs.NodejsFunction(
      this,
      'RestApiFunc',
      {
        architecture: aws_lambda.Architecture.ARM_64,
        runtime: aws_lambda.Runtime.NODEJS_20_X,
        entry: 'src/rest-api-router.ts',
      }
    );

    /**
     * REST API を作成
     */
    const restApi = new aws_apigateway.LambdaRestApi(this, 'RestApi', {
      handler: restApiFunc,
      defaultCorsPreflightOptions: {
        allowOrigins: aws_apigateway.Cors.ALL_ORIGINS,
        allowMethods: aws_apigateway.Cors.ALL_METHODS,
        allowHeaders: aws_apigateway.Cors.DEFAULT_HEADERS,
        maxAge: Duration.minutes(5),
      }, // Web アプリケーションからの CORS リクエストを許可する場合はこの記述を追加
      deployOptions: {
        stageName: 'v1', // 既定では "prod" になるため、適切なステージ名に変更
        tracingEnabled: true, // AWS X-Ray によるトレースを有効化
      },
    });

    /**
     * API Gateway エンドポイント
     */
    new CfnOutput(this, 'RestApiEndpoint', {
      value: restApi.deploymentStage.urlForPath(),
    });
  }
}

動作確認

CDK でデプロイした API Gateway のエンドポイントに対して、/companies パスへの POST メソッドのリクエストを送ると、{"Name":"Hello株式会社","id":"c123"} というレスポンスが返ってきました。Serverless Express がちゃんと動いているようです。

$ curl -X POST -H "Content-Type: application/json" \
  -d '{"Name":"Hello株式会社"}' \
  https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/v1/companies
{"Name":"Hello株式会社","id":"c123"}

同じパスでも GET メソッドでリクエストを送ると、Cannot GET /companies というエラーメッセージが返ってきます。(想定通り)

$ curl -X GET \
  https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/v1/companies
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /companies</pre>
</body>

ルーティングを設定していないパスにリクエストを送ると、Cannot POST /employees というエラーメッセージが返ってきます。(想定通り)

$ curl -X POST -H "Content-Type: application/json" \
  -d '{"Name":"Hello株式会社"}' \
  https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/v1/employees
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot POST /employees</pre>
</body>
</html>

おわりに

Serverless Express + AWS Lambda + API Gateway の構成を AWS CDK でデプロイして作成してみました。

どなたかの参考になれば幸いです。

参考

以上