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


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

環境

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だったので、それに合わせた方が無難です。

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

brew install aws-cli

プロジェクト作成

参考
https://docs.nestjs.com/

nest new project-name
>yarn

cd project-name

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

起動確認

npm run start

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

あっさり完了。

Serverless Framework用の設定

参考
https://docs.nestjs.com/faq/serverless

モジュールインストール

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にトランスパイルされるんで大丈夫な気もしますが、不測の事態を起こさないためにも。(環境周りは動かなくなると面倒)

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のエントリーポイント用のファイルを作成

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の設定を追加

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

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

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の主な変更点まとめ/

下記アクセス

http://localhost:3000/dev

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

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

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

AWSにデプロイ

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

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/
ANY - https://4w1holtb8e.execute-api.us-east-1.amazonaws.com/dev/{proxy+}
functions:
main: serverless-example-dev-main
layers:
None

成功

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

オッケー。

掃除

npx serverless remove --aws-profile profile_name
https://4w1holtb8e.execute-api.us-east-1.amazonaws.com/dev/
>{"message":"Forbidden"}

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

まとめ

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

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