AWS CDK + Lambda + API Gateway で REST APIを作成する

2023/07/26に公開

AWS CDK + Lambda + API Gateway で REST API を作成する方法について解説する。

AWS CDKとは?

インフラをコードで管理できる仕組みを Infrastructure as Code(IaC) という。Terraformなどが有名で、 AWS CDK (AWS Cloud Development Kit) も、IaCを実現するためのツールのひとつ。

AWS CDKの利点

  • プログラミング言語で記述できる(TypeScriptかPython使っている人がほとんどっぽい)。今回はTypeScriptで作成。
  • Terraformより簡単らしい。

AWS CDKの欠点

  • AWSでしか使えない。TerraformはAzureでもGCPでも使える。

事前準備

  1. AWSアカウントを作成する
  2. aws configureの設定
  3. node18系をインストール
  4. 下記のように表示されればOK
    $ node -v
    v18.15.0
    
    $ npx aws-cdk@2 --version
    2.84.0 (build f7c792f)
    

AWS CDKの初期プロジェクトを作成

$ pwd
/<任意の作業ディレクトリ>
$ mkdir aws-cdk-test
$ cd aws-cdk-test
$ npx aws-cdk@2 init app --language typescript

新規プロジェクトが作成され、下記のようなディレクトリ構成となる

$ tree -I node_modules --dirsfirst
.
├── bin
│   └── aws-cdk-test.ts
├── lib
│   └── aws-cdk-test-stack.ts
├── test
│   └── aws-cdk-test.test.ts
├── README.md
├── cdk.json
├── jest.config.js
├── package-lock.json
├── package.json
└── tsconfig.json

lib/aws-cdk-test-stack.ts があり、Stackクラスを継承したクラスが実装されている。このスタックを単位にリソースをデプロイすることになる。

lib/aws-cdk-test-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
// import * as sqs from 'aws-cdk-lib/aws-sqs';

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

    // The code that defines your stack goes here

    // example resource
    // const queue = new sqs.Queue(this, 'AwsCdkTestQueue', {
    //   visibilityTimeout: cdk.Duration.seconds(300)
    // });
  }
}

esbuildをインストール

デプロイなどをするときに必要となる。esbuildをインストールしていなければ、Dockerを使ってデプロイなどを実行する。従って、Dockerで構わないという場合はインストール不要。

$ npm install --save-dev esbuild@0

AWS Lambda関数とAPI Gatewayを作成

ここがメインパート。

まず、lib/hello-world.ts ファイルを作成する。{ message: "Hello World!" } とレスポンスを返すhandler関数を定義する。Lambdaでは特定のイベント(今回はAPI GatewayのAPIをコールすること)が発生すると、事前に設定したhandler関数が自動的に呼び出される。

lib/hello-world.ts
export const handler = async () => {
  const responseBody = { message: "Hello World!" };
  const response = {
    statusCode: 200,
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify(responseBody),
  };

  return response;
}

lib/aws-cdk-test-stack.ts を編集して、下記のように上書きする。

lib/aws-cdk-test-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Runtime } from "aws-cdk-lib/aws-lambda";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import { Construct } from 'constructs';

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

    // Lambda
    const nameHelloWorldFunc = "helloWorldFunc"
    const helloWorldFunc = new NodejsFunction(this, nameHelloWorldFunc, {
      // Lambdaが呼び出すべき関数(ハンドラ)が含まれているファイルを指定している
      entry: "lib/hello-world.ts",
      runtime: Runtime.NODEJS_18_X,
      functionName: nameHelloWorldFunc,
    });

    // API Gateway (REST API)
    const restApi = new cdk.aws_apigateway.RestApi(this, "nameRestApi", {
      deployOptions: {
        stageName: 'v1',
      },
      restApiName: `Rest_API_with_Lambda`,
    });

    // API Gatewayにリクエスト先のリソースを追加(エンドポイントの定義)
    const restApiHelloWorld = restApi.root.addResource('hello_world');

    // API GatewayのリソースにLambda関数を紐付け
    restApiHelloWorld.addMethod("GET", new cdk.aws_apigateway.LambdaIntegration(helloWorldFunc));
  }
}

Lambda関数とAPI Gatewayを作成するためのコードの編集は以上。

デプロイ

最後にAWSにデプロイをする。

$ npm run cdk deploy
省略…
Do you wish to deploy these changes (y/n)? # y で進める

aws configureの設定で指定した環境にデプロイされて、 https://xxxxxxxxxx.execute-api.xxxxxxxxxx.amazonaws.com/v1/ のようなURLが表示される。 lib/aws-cdk-test-stack.tsconst restApiHelloWorld = restApi.root.addResource('hello_world'); の箇所で、 hello_world をエンドポイントとして定義している。

従って、 https://xxxxxxxxxx.execute-api.xxxxxxxxxx.amazonaws.com/v1/hello_world にアクセスして、下記のようなレスポンスが返ってくれば完成。

{
    "message": "Hello World!"
}

参考

https://eh-career.com/engineerhub/entry/2023/04/27/093000
https://dev.classmethod.jp/articles/aws-cdk-api-gateway-lambda-rest-auth0-lambda-authorizer/
https://catalog.workshops.aws/typescript-and-cdk-for-beginner/ja-JP

Discussion