TypescriptだけでAWS Lambdaを発火させる


[PONOS Advent Calendar 2022](https://qiita.com/advent-calendar/2022/ponos) の24日目の記事です。
昨日は@bluenova1221さんの[記事](https://qiita.com/bluenova1221/items/1d6bcfdaf5600dd0289a)でした。
# なぜTypescript?
今まで静的型付け言語に慣れていたのもあり、型が指定出来ないことに不満を感じていました。
また関数先に飛んだだけでany型になることが個人的にどうなんだと思いました🤔
そこでJavascriptのファイルをローカルで作成することなくAWS Lambdaを使用してみようと思いこの記事を書きました。  

***
# 動作・開発環境
Windows 11
Powershell 7
Visual Studio Code 1.73.1
Docker Desktop 4.14.1
***

最初に`npm init`まで行います。
※前提としてnpm、dockerはインストールされているものとします。

```powershell:Powershell 7
C:\Users\username> cd ~
C:\Users\username\Desktop> mkdir HelloWorld
C:\Users\username\Desktop> cd HelloWorld
C:\Users\username\HelloWorld> npm init
```

色々聞かれますがすべてEnterを押してください。

次にトランスパイルするためにesbuildの型定義ファイルをインストールします。

```powershell:Powershell 7
C:\Users\username\HelloWorld> npm install -D @types/aws-lambda esbuild
```

次に`index.ts`と`Dockerfile`を作成します。
```powershell:Powershell 7
C:\Users\username\HelloWorld> New-Item -Path . -Name "index.ts" -ItemType "file"
C:\Users\username\HelloWorld> New-Item -Path . -Name "Dockerfile" -ItemType "file"
```

次に`index.ts`と`Dockerfile`に以下の内容を記載します。

```dockerfile:Dockerfile
FROM public.ecr.aws/lambda/nodejs:16 as builder
WORKDIR /usr/app
COPY package.json index.ts  ./
RUN npm install
RUN npm run build
    

FROM public.ecr.aws/lambda/nodejs:16
WORKDIR ${LAMBDA_TASK_ROOT}
COPY --from=builder /usr/app/dist/* ./
CMD ["index.handler"]
```

```typescript:index.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',
        }),
    };
};
```

次に`package.json`のscriptsに以下を追記します。
```json:package.json
 "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "esbuild index.ts --bundle --minify --sourcemap --platform=node --target=es2020 --outfile=dist/index.js"
  }
```

ここまで実装したら`docker build`を走らせます。

```powershell:Powershell 7
C:\Users\username\HelloWorld> docker build -t hello-world .
```

次にAWS CLIの操作に移ります。
初めてAWS CLIを操作する方は`aws configure`に情報が登録されていないためエラーになると思います。
その為最初に設定を行います。
なおアクセスキーとシークレットキーはIAMからダウンロードできるので、それに書かれている情報を入力してください。
リージョンは東京リージョンを使用するため`ap-northeast-1`に設定してください。

```powershell:Powershell 7
C:\Users\username\HelloWorld> aws configure
AWS Access Key ID [None]: IAMからダウンロードしたcsvのアクセスキー
AWS Secret Access Key [None]: IAMからダウンロードしたcsvのシークレットキー
Default region name [None]: ap-northeast-1
Default output format [None]:
```

設定ができましたらログインを行います。
`123456781234`の箇所はログイン時に使用したエイリアス(12桁)に変更してください。

```powershell:Powershell 7
C:\Users\username\HelloWorld> aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 123456781234.dkr.ecr.ap-northeast-1.amazonaws.com
```

ログインができると`Login Succeeded`とターミナルに表示されます。
成功したら次に、ECRを作成するので以下のコマンドを実行します。

```powershell:Powershell 7
C:\Users\username\HelloWorld> aws ecr create-repository --repository-name hello-world --image-scanning-configuration scanOnPush=true --image-tag-mutability MUTABLE
```

これでECRに`hello-world`というリポジトリが作成されます。
そして最後にタグをつけてECRにpushまで行います。

```powershell:Powershell 7
C:\Users\username\HelloWorld> docker tag  hello-world:latest 123456781234.dkr.ecr.ap-northeast-1.amazonaws.com/hello-world:latest

C:\Users\username\HelloWorld> docker push 123456781234.dkr.ecr.ap-northeast-1.amazonaws.com/hello-world:latest
```

ここまで出来ましたらターミナルでの操作が一通り終了しました。
次にAWS側で`Lambda`,`API Gateway`を設定していきます。

# Lambda

関数の作成　→　コンテナイメージを選択します。

![スクリーンショット_20221213_101624.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398501/abb43a3d-0a2a-2a46-59ff-79312bbc5bc2.png)

次に関数名、コンテナイメージを設定します。
関数名はお好きな名前で設定してください。
今回私は`hello-world-function`と設定します。

関数名・hello-world-function

コンテナイメージ URI:
1.イメージを設定
2.Amazon ECR イメージリポジトリをのタブをクリック
3.`hello world`を選択
4.`latest`のタグをクリックしてイメージを選択するをクリック

以下の画像のようになれば`関数の作成`をクリックしてください。

![スクリーンショット 2022-12-13 102329.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398501/815ee695-6cde-7829-e859-248cabd90698.jpeg)


関数の作成には少し時間がかかるので、このタイミングでAPI Gatewayの構築、設定を行います。

# API Gateway

API Gatewayに飛びましたら、`HTTP API`の構築をクリックしてください。

次に`統合`のタブをクリック、`Lambda`を選択してください。

選択すると`Lambda関数`の入力ボックスがでてきますのでクリックしてください。
クリックしますと先程作成したLambda関数の関数名が出てくるのでクリックして選択します。

次にAPI名を入力します。
ここもお好きな名前を入力してください。
今回私は`helloworld`と入力します。

ここまで設定ができましたら以下のようになります。

![スクリーンショット 2022-12-13 105458.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398501/e0499e9c-7a99-2d92-46b0-96f15167a922.jpeg)

ここまで設定ができましたら次へをクリックし`ルートを設定`する画面に遷移します。

デフォルトでメソッドが`ANY`になっているのでこれを`GET`に変更し次へをクリックします。

`ステージを定義`のページを遷移しますが、こちらは何も変更せず次へをクリックします。

最終的に以下のようになっていることを確認し作成をクリックします。


![スクリーンショット 2022-12-13 110435.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398501/b9b2c694-2bdb-15c8-4448-cd5ef08fb995.jpeg)


作成が完了しますとAPI Gatewayの画面に遷移し以下の画像のようになります。

![スクリーンショット 2022-12-13 111127.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398501/1e895064-76b9-5c43-da56-8485a5c1007c.jpeg)


最後ブラウザのアドレスバーに
API Gatewayの`URLを呼び出す`のURL + /hello-world-function(Lambda作成時に設定した関数名)
を入力しEnterを押しますと...

```
{"message":"hello world"}
```

と表示されます！

# 最後に

ここまで見てくださりありがとうございました。
型があるとないとで個人的に安心感が全然違います。
各種サービスのTypescriptのSDK・CDKが配布されているのでもっと実験していきたいと思います。

# 参考・引用
[コンテナイメージを使用して、トランスパイルされた TypeScript コードを Lambda にデプロイする](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/typescript-image.html)

# 次回(ラスト)
[PONOS Advent Calendar 2022](https://qiita.com/advent-calendar/2022/ponos)の最後を飾るのは@oryzae29さんです！
お楽しみに！