@vendia/serverless-express(旧aws-serverless-express)でExpressアプリをAPIGateway+Lambdaにデプロイしてみた
吉川@広島です。
APIGateway+LambdaExpressアプリをデプロイできる@vendia/serverless-expressをデプロイして試してみました。
@vendia/serverless-expressについて
APIGateway+Lambda上でExpressを動かせるというライブラリです。
昔はaws-serverless-expressというパッケージがあってこちらが使われていた認識なのですが、@vendia/serverless-expressがその後継という形のようです。
AWS Serverless Express has moved On 11/30, the AWS Serverless Express library moved from AWS to Vendia and will be rebranded to @vendia/serverless-express. Similarly, the aws-serverless-express NPM package will be deprecated in favor of @vendia/serverless-express.
READMEにも「aws-serverless-expressから@vendia/serverless-expressに移行したよ」とありますね。
本手法のメリット/デメリット
【新機能】Amazon API Gatewayの設定方法にcatch-allパス変数、ANYメソッド、Lambdaとの新しいプロキシ連携の3機能が追加。 | DevelopersIO
@vendia/serverless-express+APIGatewayの {proxy+}
パス と ANY
メソッドですべてのルーティングを1つのLambda関数で捌く構成になります。これは以下のブログでもあるように、
CDKを使って、一つのLambda関数でAPI設計してみた | DevelopersIO
一つのLambda関数だけを用いた構成だと、Lambda関数が一つであるためデプロイの時間を短くすることができるというメリット
があります。
そして通常であれば、
複数のAPIを作るために一つのLambda関数内で、httpメソッド(GET,POST,PUT,DELETE)ごとに条件分岐を行い、さらにURLごとに条件分岐する必要があります。
という煩わしさが生じるデメリットがあるのですが、@vendia/serverless-expressを使えば馴染み深いExpressのルーティングを利用できるのでその短所も打ち消すことができます。
また、Expressアプリケーションなのでローカルサーバを起動しての動作確認が行いやすいこともメリットといえそうです。
気になる点を挙げるとすれば、王道のAPIGW+Lambda Wayとはいえず、ややHackyな手法ではあると思います。ExpressのようなWeb Application Frameworkを使うならECSやAppRunnerを使う方が素直な感じはします。それでもECSなどを使う場合と比べてLambdaにはゼロスケール1できるという強みがあるので、存外悪くない手法だと思います。
それではやっていきます。
環境
- node 16.14.0
- typescript 4.5.5
- aws-cdk 2.12.0
- express 4.17.2
- @vendia/serverless-express 4.5.3
ソースコード全体
GitHubにアップロードしています。
cm-dyoshikawa/serverless-express-playground
Lambdaコード
// packages/server/src/index.ts import serverlessExpress from '@vendia/serverless-express' import express from 'express' import cors from 'cors' const app = express() app.use(cors()) app.use(express.json()) app.get('/hello', (_, res) => { res.status(200).send({ message: 'Hello serverless-express', }) }) app.get('/ping', (_, res) => { res.status(200).send({ message: 'pong', }) }) export const handler = serverlessExpress({ app })
/hello
と /ping
のルーティングを作ってみました。
CDKコード
AWS CDK v2で構成管理します。
import { Construct } from 'constructs' import { Stack, StackProps, aws_lambda, aws_apigateway } from 'aws-cdk-lib' export class IacStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props) const fn = new aws_lambda.Function(this, 'fn', { code: aws_lambda.Code.fromAsset('../server/dist'), handler: 'index.handler', runtime: aws_lambda.Runtime.NODEJS_14_X, environment: { NODE_OPTIONS: '--enable-source-maps', }, }) const api = new aws_apigateway.RestApi(this, 'api', { defaultCorsPreflightOptions: { allowOrigins: aws_apigateway.Cors.ALL_ORIGINS, allowMethods: aws_apigateway.Cors.ALL_METHODS, allowHeaders: aws_apigateway.Cors.DEFAULT_HEADERS, }, }) api.root.addProxy({ defaultIntegration: new aws_apigateway.LambdaIntegration(fn), }) } }
NODE_OPTIONS: '--enable-source-maps'
はsourcemap対応です。下記をご参考ください。
TypeScript+Node.jsでsourcemap対応を加えてエラーログ調査を行いやすくしたい | DevelopersIO
IacStack
のIacはInfrastructure as Codeのことでそれ以上の意味は特にありません。
addProxy()
を使わずに addResource()
と addMethod()
を使って下記のようにも書けるようでしたので併記しておきます。
- api.root.addProxy({ - defaultIntegration: new aws_apigateway.LambdaIntegration(fn), - }) + api.root + .addResource('{proxy+}') + .addMethod('ANY', new aws_apigateway.LambdaIntegration(fn))
curlで叩いてみる
npm scriptsを組んでありますので npm run deploy
でデプロイしてcurlで叩きます。
curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/hello {"message":"Hello serverless-express"}
curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/ping {"message":"pong"}
意図通りの動作確認が取れました。
参考
- express.jsのcors対応 - Qiita
- 【新機能】Amazon API Gatewayの設定方法にcatch-allパス変数、ANYメソッド、Lambdaとの新しいプロキシ連携の3機能が追加。 | DevelopersIO
- [AWS CDK超入門] DynamoDB + Lambda + API GatewayでAPIを作ってみた | DevelopersIO
- [AWS CDK] API Gateway(REST API)のCORSの動作を確認してみた | DevelopersIO
- TypeScript+Node.jsでsourcemap対応を加えてエラーログ調査を行いやすくしたい | DevelopersIO
- アクセスがない場合、起動インスタンスがゼロになることです。メリットはその間のクラウド課金を抑えられることが主なメリットです。こちらのブログなど参考になるかもしれません。[#ServerlessDays 2019]Zero Scale Abstraction in Knative Serving | DevelopersIO ↩