AWS CDKでTypeScriptのLambda関数をデプロイしてみた

公式ドキュメント通りに作成します

https://docs.aws.amazon.com/lambda/latest/dg/typescript-package.html#aws-cdk-ts

## CDKのプロジェクト作成

```bash
$ mkdir hello-world
$ cd hello-world
$ cdk init app --language=typescript   # cdkプロジェクトの初期化
$ npm install -D @types/aws-lambda     # 型定義のインストール
```

## TypeScirptコード作成
```bash
$ touch lib/hello-world.function.ts
$ touch lib/hello-world.ts
```

```typescript:lib/hello-world.function.ts
import { Context, APIGatewayProxyResult, APIGatewayEvent } from 'aws-lambda';

export const handler = async (event: APIGatewayEvent, context: Context): Promise<APIGatewayProxyResult> => {
  console.log(`Event: ${JSON.stringify(event, null, 2)}`);
  console.log(`Context: ${JSON.stringify(context, null, 2)}`);
  return {
    statusCode: 200,
    body: JSON.stringify({
      message: 'hello world',
    })
  };
};
```

```typescript:lib/hello-world.ts
import { Construct } from "constructs";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import { LambdaRestApi } from "aws-cdk-lib/aws-apigateway";

export class HelloWorld extends Construct {
  constructor(scope: Construct, id: string) {
    super(scope, id);
    const helloFunction = new NodejsFunction(this, 'function');
    new LambdaRestApi(this, 'apigw', {
      handler: helloFunction
    })
  }
}
```

```typescript:lib/hello-world-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { HelloWorld } from './hello-world';

export class HelloWorldStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    new HelloWorld(this, 'hello-world');
  }
}
```

## cdk synthでエラー
構築結果を確認するため```cdk synth```を実行したところ、エラー。
```
$ cdk synth
[+] Building 1.4s (3/3) FINISHED                                                                                                                                                                           docker:default
 => [internal] load build definition from Dockerfile                                                                                                                                                                 0.0s
 => => transferring dockerfile: 1.30kB                                                                                                                                                                               0.0s
 => ERROR [internal] load metadata for public.ecr.aws/sam/build-nodejs18.x:latest                                                                                                                                    1.4s
 => [auth] aws:: sam/build-nodejs18.x:pull token for public.ecr.aws                                                                                                                                                  0.0s
------
 > [internal] load metadata for public.ecr.aws/sam/build-nodejs18.x:latest:
------
Dockerfile:4
--------------------
   2 |     # passed as build arg. The default allows to do `docker build .` when testing.
   3 |     ARG IMAGE=public.ecr.aws/sam/build-nodejs18.x
   4 | >>> FROM $IMAGE
   5 |     
   6 |     # Install yarn
--------------------
ERROR: failed to solve: public.ecr.aws/sam/build-nodejs18.x: failed to resolve source metadata for public.ecr.aws/sam/build-nodejs18.x:latest: unexpected status from HEAD request to https://public.ecr.aws/v2/sam/build-nodejs18.x/manifests/latest: 403 Forbidden
```

原因不明ですが解決方法は以下。ECRにログインして手動でpullしたところエラーが解消しました。

```
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws
docker pull public.ecr.aws/sam/build-nodejs20.x --platform="linux/amd64"
```
https://zenn.dev/fagai/articles/f90144dd3a392a

## cdk deploy実行
```
$ cdk deploy
略
✨  Total time: 51.37s
```
無事デプロイに成功されました。
デプロイ結果をAWSのコンソールで確認したところ、API GatewayがLambdaのトリガーに設定されていました。ですがAPI Gatewayのステージが作成されておらず動作しないため、トリガーで設定されたステージ名に合わせて作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3770153/7c01a575-b613-d5e7-31e8-42ce0124f189.png)

今回はステージ名を```prod```として作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3770153/798975bb-97a8-77cf-5941-94df84ba5901.png)

動作確認。無事応答が返ってきましたので、問題なしです。
```
> curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod
{"message":"hello world"}
```