はじめに
最近Expressで作ったAPIを、aws-serverless-expressを使ってサーバレス化したときの手順をまとめる。
今回はExpressをサーバレス化する話なので、Expressを使ったAPIの構築については触れない。
前提
- Expressで既にAPIを作っている
- AWSアカウントを持っている
- aws-cliが設定済みである
aws-serverless-expressとは
awslabが出してる、Expressで作ったRESTful APIをサーバレス化するツール。
サーバレスAPIは、Express + Lambda + API Gatewayを用いて構築する。
このツールの凄いところは、アプリケーションでいじるところが殆ど無いところだ。
なので、既にExpressでAPIサーバを構築している人なら、少しの手順を踏むだけで、サーバレスなAPIを簡単に構築することができる。
細かいことはGithubのREADMEに書いてある。
天下のAWSさんが出しているだけあって、exampleもちゃんとしてる。
1からAPIを作る人はexampleをコピーするところから始めると良いと思う。
Githubのリンクはこちら。
サーバレス化
1. aws-serverless-expressのインストール
以下を実行して、aws-serverless-expressをインストール。
$ npm install --save aws-serverless-express
2. exampleのpackage.jsonのscriptsをコピー
aws-serverless-expressのexampleには、既に便利なscriptが用意されているため、今回はそれを利用する。
自分のプロジェクトのpackage.jsonに以下をコピペする。
(Windows以外の人はwin-config以下はコピペする必要なし)。
"scripts": {
"start": "node app.local.js",
"config": "node ./scripts/configure.js",
"deconfig": "node ./scripts/deconfigure.js",
"local": "node scripts/local",
"invoke-lambda": "aws lambda invoke --function-name $npm_package_config_functionName --region $npm_package_config_region --payload file://api-gateway-event.json lambda-invoke-response.json && cat lambda-invoke-response.json",
"create-bucket": "aws s3 mb s3://$npm_package_config_s3BucketName --region $npm_package_config_region",
"delete-bucket": "aws s3 rb s3://$npm_package_config_s3BucketName --region $npm_package_config_region",
"package": "aws cloudformation package --template ./cloudformation.yaml --s3-bucket $npm_package_config_s3BucketName --output-template packaged-sam.yaml --region $npm_package_config_region",
"deploy": "aws cloudformation deploy --template-file packaged-sam.yaml --stack-name $npm_package_config_cloudFormationStackName --capabilities CAPABILITY_IAM --region $npm_package_config_region",
"package-deploy": "npm run package && npm run deploy",
"delete-stack": "aws cloudformation delete-stack --stack-name $npm_package_config_cloudFormationStackName --region $npm_package_config_region",
"setup": "npm install && (aws s3api get-bucket-location --bucket $npm_package_config_s3BucketName --region $npm_package_config_region || npm run create-bucket) && npm run package-deploy",
"win-config": "npm run config",
"win-deconfig": "npm run deconfig",
"win-local": "npm run local",
"win-invoke-lambda": "aws lambda invoke --function-name %npm_package_config_functionName% --region %npm_package_config_region% --payload file://api-gateway-event.json lambda-invoke-response.json && cat lambda-invoke-response.json",
"win-create-bucket": "aws s3 mb s3://%npm_package_config_s3BucketName% --region %npm_package_config_region%",
"win-delete-bucket": "aws s3 rb s3://%npm_package_config_s3BucketName% --region %npm_package_config_region%",
"win-package": "aws cloudformation package --template ./cloudformation.yaml --s3-bucket %npm_package_config_s3BucketName% --output-template packaged-sam.yaml --region %npm_package_config_region%",
"win-deploy": "aws cloudformation deploy --template-file packaged-sam.yaml --stack-name %npm_package_config_cloudFormationStackName% --capabilities CAPABILITY_IAM --region %npm_package_config_region%",
"win-package-deploy": "npm run win-package && npm run win-deploy",
"win-delete-stack": "aws cloudformation delete-stack --stack-name %npm_package_config_cloudFormationStackName% --region %npm_package_config_region%",
"win-setup": "npm install && (aws s3api get-bucket-location --bucket %npm_package_config_s3BucketName% --region %npm_package_config_region% || npm run win-create-bucket) && npm run win-package-deploy"
}
次に、exampleで使用しているscriptファイルや、yamlファイルをコピーする必要がある。
プロジェクトルートで以下を実行。
$ git clone https://github.com/awslabs/aws-serverless-express.git ase
$ cp -r ase/example/scripts .
$ cp ase/example/api-gateway-event.json .
$ cp ase/example/cloudformation.yaml .
$ cp ase/example/lambda.js .
$ cp ase/example/simple-proxy-api.yaml .
$ rm -rf ase
3. awsアカウントとs3バケットの設定
先程コピーしたスクリプトを使用して、awsアカウントとs3バケットの設定を行う。
$ npm run config -- \
--account-id="<accountId>" \
--bucket-name="<bucketName>" \
--region="<region>" \ # optinal
--function-name="<functionName>" # optinal
このコマンドの実行が成功すると、以下の3つのファイルが書き換わる。
- package.json
- simple-proxy-api.yaml
- cloudformation.yaml
4. app.jsの修正
Expressをaws-serverless-expressで動かすには少しコードに手を加えなくてはならない。
まず、app.jsでaws-serverless-expressのMiddlewareを有効化する必要がある。
以下をapp.jsに追加
const express = require('express')
+ const awsServerlessExpressMiddleware = require('aws-serverless-express/middleware')
const app = express()
+ app.use(awsServerlessExpressMiddleware.eventContext())
次に、aws-serverless-expressではUNIXドメインソケットで別の箇所でlistenしているらしいので、app.jsに書いてるlistenメソッドは削除する必要がある。
- app.listen()
最後に、lambda.jsでapp.jsを読み込む必要があるため、app.jsをmodule化する必要がある。
以下の一文をapp.jsの末尾に追加
+ module.exports = app
5. lambda.jsの修正
exampleからコピーした、lambda.jsを修正する。
先程修正したapp.jsのパスを指定して、importするだけで良い。
const awsServerlessExpress = require('aws-serverless-express')
- const app = require('./app')
+ const app = require('./path/to/app')
6. デプロイ
exampleで用意されているsetupスクリプトを実行するだけで良い。
$ npm run setup
setupスクリプトを実行すると以下が順番に実行される。
- npm install
- デプロイ先のs3バケットの作成
- CloudFormationのテンプレートの作成
- CloudFormationのデプロイ
3.
で生成されるCloudFormationのテンプレートはpackaged-sam.yamlというファイルに出力される。
packaged-sam.yamlの内容は以下の通り
- API Gatewayの構築
- Lambda Functionの作成
- Lambdaの実行権限のあるIAMロールの作成
setupスクリプトの実行が成功していれば、CloudFormationのStackが実行されているはずなので、AWSコンソールにログインして、CloudFormationが実行されているか確認する。
7. 確認
AWSコンソールにサインインし、API Gatewayサービスを選択。
新しくAPIが作成されていることを確認する。
新しく作成されたAPIを選択し、「ステージ > prod > URLの呼び出し」に書かれているURLをBase URLとしてAPIを叩いてみる。
Expressで予め作成したAPIを実行して、動くことを確認する。
以下は例。
$ curl http://hogehoge.execute-api.ap-northeast-1.amazonaws.com/prod/v1/fuga
まとめ
Expressを使って既に動いているAPIを、たった7つのステップで、簡単にサーバレス化できてしまった。
これからサーバレス、マイクロサービスがトレンドになる中、簡単に既存のAPIをサーバレス化できてしまう仕組みは本当に凄いと思った。流石AWSさん。
API Gatewayの作成まではできたので、後は独自ドメインにしたりhttpsを有効化したり、色々カスタマイズすると良いと思う。
自分はめんどくさがって手動でポチポチ設定してしまったが、本当はこの辺もCloudFormationでできるはずなので、暇になったら設定してみる。