「NestJS」をAWS Lambda + API Gatewayで動かす
どうも!大阪オフィスの西村祐二です。
個人的にフロントエンドはAngularを使ってよく開発しています。
AngularはTypeScriptがデフォルトなので、APIのレスポンスを型定義するのですが、サーバーサイドもTypeScriptにして型定義を共有できたら良さそうだなと思っていました。
そこで最近、TypeScript製Node.jsフルスタックフレームワーク「NestJS」を調べています。
「NestJS」のイメージとしてはPythonの「Flask」やRubyの「Rails」を想像してもらえれば良いかと思います。
今回はその「NestJS」をAWS Lambda + API Gatewayのサーバーレス構成で動かしてみたいと思います。
環境
- Node: 12.13.0
- NestJS: 6.10.1
- Serverless Framework: 1.57.0
作業概要
Angular同様にNestJSもCLIが提供されていますので、それを使ってプロジェクトを作成します。
LambdaへのデプロイはServerless Frameworkを使ってデプロイします。
node_modulesの容量が大きくなってしまうので、Lambda Layersを利用します。
Lambda Layersへのデプロイを簡単にするためにプラグインの「serverless-layers」を使用します。
試してみる
環境準備
パッケージをインストールします。
1 2 | $ npm i -g @nestjs/cli$ npm i -g serverless |
NestJSのプロジェクト作成
NestJSのCLIを使ってプロジェクトを作成します。
今回は「serverless-nestjs」としています。
1 2 3 | $ nest new serverless-nestjs? Which package manager would you ❤️ to use? npm |
プロジェクトが作成できたら、ローカルで実行しています。
1 2 | $ cd serverless-nestjs$ npm run start |
ブラウザをひらき、「http://localhost:3000」にアクセスし
Hello World!
と表示されればOKです。
次はNestJSがLambdaで動くようにハンドラーファイルを作成します。
Lambda用のハンドラーファイルを作成
必要なライブラリをインストールします。
1 | $ npm i aws-lambda aws-serverless-express express |
API Gatewayからデータを受けとるためのLambdaハンドラーを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | import { Context, Handler } from 'aws-lambda';import { NestFactory } from '@nestjs/core';import { AppModule } from './app.module';import { Server } from 'http';import { ExpressAdapter } from '@nestjs/platform-express';import * as serverless from 'aws-serverless-express';import * as express from 'express';let cachedServer: Server;function bootstrapServer(): Promise<Server> { const expressApp = express(); const adapter = new ExpressAdapter(expressApp); return NestFactory.create(AppModule, adapter) .then(app => app.enableCors()) .then(app => app.init()) .then(() => serverless.createServer(expressApp));}export const handler: Handler = (event: any, context: Context) => { if (!cachedServer) { bootstrapServer().then(server => { cachedServer = server; return serverless.proxy(server, event, context); }); } else { return serverless.proxy(cachedServer, event, context); }}; |
Serverless Frameworkの設定
プラグインをインストールします。
1 | $ npm i -D serverless-layers |
Layerをデプロイするために事前にS3にバケットを作成しておきます。
今回は「nestjs-lambda-layers」というバケットを作成しておきました。
NestJSはビルドコマンドでTypeScriptのファイルをJSに変換し、dist/に出力してくれるので、そのファイルをデプロイパッケージに含めデプロイします。
node_modulesのファイルはserverless-layersを使ってLayerとして紐付けます。
作成するAPI GatewayはAnyとして受け取ったリクエストはすべてLambdaで動くNestJSに渡すようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | service: serverless-nestjsprovider: name: aws runtime: nodejs10.x region: ap-northeast-1plugins: - serverless-layerscustom: serverless-layers: layersDeploymentBucket: nestjs-lambda-layerspackage: individually: true include: - dist/** exclude: - '**'functions: index: handler: dist/index.handler events: - http: cors: true path: '/' method: any - http: cors: true path: '{proxy+}' method: any |
これで準備完了です。
デプロイしてみる
下記コマンドを実行して、デプロイしてみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | $ nest build && sls deployServerless: [LayersPlugin]: Downloading package.json from bucket...Serverless: [LayersPlugin]: package.json does not exists at bucket...Serverless: [LayersPlugin]: Dependencies has changed! Re-installing...npm WARN serverless-nestjs@0.0.1 No descriptionnpm WARN serverless-nestjs@0.0.1 No repository field.> @nestjs/core@6.10.1 postinstall /Users/yuji/study/nestjs/serverless-nestjs/.serverless/layers/nodejs/node_modules/@nestjs/core> opencollective || exit 0added 161 packages from 151 contributors and audited 885260 packages in 6.078sfound 0 vulnerabilitiesServerless: [LayersPlugin]: Created layer package /Users/yuji/study/nestjs/serverless-nestjs/.serverless/serverless-nestjs-dev.zip (13.6 MB)Serverless: [LayersPlugin]: Uploading layer package...Serverless: [LayersPlugin]: OK...Serverless: [LayersPlugin]: New layer version published...Serverless: [LayersPlugin]: Uploading remote package.json...Serverless: [LayersPlugin]: OK...Serverless: [LayersPlugin]: Associating layers...Serverless: [LayersPlugin]: function.index - arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxxxxxxx:layer:serverless-nestjs-dev:2Serverless: Packaging service...Serverless: Excluding development dependencies...Serverless: Creating Stack...Serverless: Checking Stack create progress...........Serverless: Stack create finished...Serverless: Uploading CloudFormation file to S3...Serverless: Uploading artifacts...Serverless: Uploading service index.zip file to S3 (42.58 KB)...Serverless: Validating template...Serverless: Updating Stack...Serverless: Checking Stack update progress..........................................Serverless: Stack update finished...Service Informationservice: serverless-nestjsstage: devregion: ap-northeast-1stack: serverless-nestjs-devresources: 14api keys: Noneendpoints: ANY - https://xxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/ ANY - https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/{proxy+}functions: index: serverless-nestjs-dev-indexlayers: NoneServerless: [LayersPlugin]: function.index = layers.arn:aws:lambda:ap-northeast-1:xxxxxxxx:layer:serverless-nestjs-dev:2Serverless: Run the "serverless" command to setup monitoring, troubleshooting and testing. |
上記のようなログがでれば成功です!
これで、LambdaでNestJSが動く、API Gateway+Lambdaの構成ができました!簡単ですね。
デプロイしたAPIを叩いてみる
上記でAPI Gateway+Lambdaの構成ができたので実際に動かしてみたいと思います。
ログ出力のendpointsのところに出力されたURLにブラウザからアクセスしてみましょう。
するとローカル実行で確認したのと同じように「Hello World!」が出力されるかと思います!やりましたね!
さいごに
「NestJS」をAWS Lambda + API Gatewayの構成で動かしてみました。
「NestJS」はAngularのように開発できたり、CLIでローカル実行やビルド、テストなどが実行できたりと、いろんな機能が予め用意されているので、環境構築に手間がかからず、すぐに開発に取りかかれて良いです。
さらに、Serverless Frameworkを使えば、簡単に「NestJS」が動くAPI Gateway+Lambdaの構成を構築できます。
次はAngular+NestJSで実践的なものを作ってみたいと思います。
誰かの参考になれば幸いです。