0からNestJSを組もう(AWS Lambda)

NestJSが少し前にV8になったというのもあり、確認も含め１から構築してみました。
基本的に公式通り組んでます。

# 環境

| PC | OS |
|-|-|
| mac | m1 Big Sur 11.4|

| tool | version | |
| - |-|-|
| nodejs|v16.8.0|　※ここは14に合わせる方が良いかと。|
|aws-cli| 2.2.21||

|aws|version|
|-|-|
|Lambda|node v14.x|

|deploy|
|-|
|Serverless Framework|

# Nestプロジェクトの作成

## 事前準備

パッケージ管理はお好きなもので。
nodeは今の最新で。
プロジェクト内はyarn使います。
## node

※後述してますが、LambdaのNodeのruntimeが最新v14だったので、それに合わせた方が無難です。

```bash
asdf global nodejs 16.8.0

node -v
> v16.8.0

npm i -g npm
npm i -g yarn
npm i -g @nestjs/cli

nest -v
8.1.1
```

## aws-cli
m1でasdfがパッとうまくいかなかったので、こっちはbrew

```bash
brew install aws-cli
```

## プロジェクト作成

参考
[https://docs.nestjs.com/](https://docs.nestjs.com/)

```bash
nest new project-name
>yarn

cd project-name

# プロジェクトでのnodejsバージョン設定。（なぜかv付けない）
asdf local nodejs 16.8.0
```

## 起動確認

```bash
npm run start

http://localhost:3000/
>Hello World!
```

あっさり完了。

# Serverless Framework用の設定

参考
[https://docs.nestjs.com/faq/serverless](https://docs.nestjs.com/faq/serverless)

## モジュールインストール

```bash
yarn add @vendia/serverless-express aws-lambda
yarn add @types/aws-lambda serverless-offline
```

## serverless.yamlの作成

ここで、lambdaがnodejs14までしか対応していないことを思い出す、、、
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-runtimes.html

一旦このままで行きます。

※結果としてはこれでもいけました。がこの辺り合わせた方が良いかと。jsにトランスパイルされるんで大丈夫な気もしますが、不測の事態を起こさないためにも。（環境周りは動かなくなると面倒）

```bash
echo "service:
  name: serverless-example

plugins:
  - serverless-offline

provider:
  name: aws
  runtime: nodejs14.x

functions:
  main:
    handler: dist/index.handler
    events:
      - http:
          method: ANY
          path: /
      - http:
          method: ANY
          path: '{proxy+}'" > serverless.yaml
```

※runtimeのバージョンとhandlerの名前を変えてます。

## Lambdaのエントリーポイント用のファイルを作成

```bash
echo "import { NestFactory } from '@nestjs/core';
import serverlessExpress from '@vendia/serverless-express';
import { Callback, Context, Handler } from 'aws-lambda';
import { AppModule } from './app.module';

let server: Handler;

async function bootstrap(): Promise<Handler> {
  const app = await NestFactory.create(AppModule);
  await app.init();

  const expressApp = app.getHttpAdapter().getInstance();
  return serverlessExpress({ app: expressApp });
}

export const handler: Handler = async (
  event: any,
  context: Context,
  callback: Callback,
) => {
  server = server ?? (await bootstrap());
  return server(event, context, callback);
};" > src/index.ts
```

※変えたhandlerの名前でファイル作成しています。

## tsconfig.jsonに、esModuleInteropの設定を追加

```bash
{
  "compilerOptions": {
    ...
    "esModuleInterop": true
  }
}
```

## ビルドとlocal確認の環境を立ち上げ確認

```bash
npm run build
npx serverless offline
```

なんか出た。

> Need to install the following packages:
serverless
Ok to proceed? (y)

入っていないパッケージを使用すると警告が出るらしいです。
yで。（エラー出たらそこで解決しようと思ったら、すんなりいけた）

解説はここ見ました。
[https://blog.watilde.com/2020/10/14/npm-v7の主な変更点まとめ/](https://blog.watilde.com/2020/10/14/npm-v7%E3%81%AE%E4%B8%BB%E3%81%AA%E5%A4%89%E6%9B%B4%E7%82%B9%E3%81%BE%E3%81%A8%E3%82%81/)

下記アクセス

```bash
http://localhost:3000/dev
```

エラー、
/のパスだと、なぜか解決できないっぽい。

```bash
http://localhost:3000/dev//
>Hello World!
```

これだといけた。
オッケーで。(パス設定しての確認は大丈夫だったので)

# AWSにデプロイ

aws-cliが入っていて、プロファイルも設定している想定です。

```bash
npx serverless deploy --stage dev --aws-profile profile_name
```

> Serverless: Stack update finished...
Service Information
service: serverless-example
stage: dev
region: us-east-1
stack: serverless-example-dev
resources: 12
api keys:
None
endpoints:
ANY - [https://4w1holtb8e.execute-api.us-east-1.amazonaws.com/dev/](https://4w1holtb8e.execute-api.us-east-1.amazonaws.com/dev/)
ANY - [https://4w1holtb8e.execute-api.us-east-1.amazonaws.com/dev/{proxy+}](https://4w1holtb8e.execute-api.us-east-1.amazonaws.com/dev/%7Bproxy+%7D)
functions:
main: serverless-example-dev-main
layers:
None

成功

```bash
https://4w1holtb8e.execute-api.us-east-1.amazonaws.com/dev/
>Hello World!
```

オッケー。

## 掃除

```bash
npx serverless remove --aws-profile profile_name
```

```bash
https://4w1holtb8e.execute-api.us-east-1.amazonaws.com/dev/
>{"message":"Forbidden"}
```

見れなくなってオッケー。（一応マネコン見て、ないのを確認）

## まとめ

公式に沿ったら、結構すんなりいけました。
最近のものは、手順が丁寧でありがたいです。

あとは、これをどう応用していこうかなーという感じです。
参考までに。