Node.js(TypeScript版)でServerless Frameworkの環境を作っていきます。
検証した環境
1 | yarn | 1.22.4 |
2 | serverless | 2.8.0 |
前準備
プロジェクトの初期化を行うため serverless
コマンドをグローバルで使えるようにインストールします。
# システム全体で使えるようにする
$ npm i -g serverless
# インストール出来た事の確認
$ serverless -v
Framework Core: 2.8.0
Plugin: 4.1.1
SDK: 2.3.2
Components: 3.2.3
serverless
コマンドはインストールした時点で sls
という短縮コマンドが使えるようになります。
# インストール時点で短縮コマンドが使える
$ sls -v
Framework Core: 2.8.0
Plugin: 4.1.1
SDK: 2.3.2
Components: 3.2.3
プロジェクトを初期化
ここではNode.jsのTypeScript版で初期化します。
私は「serverless-ts-sample」というフォルダにプロジェクトを作っていきます
$ cd <プロジェクトフォルダ>
# プロジェクトフォルダでServerless Frameworkの雛形を作るためのコマンドを実行
$ sls create -t aws-nodejs-typescript
このコマンドを実行するとフォルダ直下にファイルやフォルダがいくつか作られます
serverless-ts-sample/
.gitignore
.vscode/
handler.ts
package.json
README.md
serverless.ts
tsconfig.json
webpack.config.js
プロジェクト初期化時のコマンドについて(余談)
実行フォルダ直下にファイル群を作るか、フォルダの中にまとめた状態で作るか、で実行する $ sls create
コマンドが変わってきます。( -p <プロジェクト名>
を付与するかどうかの違い)
例えば「hoge/」というフォルダで
$ sls create -t aws-nodejs-typescript -p fuga
と実行すると
hoge/
fuga/
handler.ts
package.json
・・・
となり、
$ sls create -t aws-nodejs-typescript
と実行すると
hoge/
handler.ts
package.json
・・・
となります。
プロジェクトに serverless を導入
この時点だとプロジェクト内に serverless
のパッケージが存在していません。
そのため以下のコマンドで追加します
# プロジェクトにserverlessをインストール
$ yarn add serverless
・・・
✨ Done in 10.68s.
# プロジェクト内のserverlessのバージョン確認
$ npx sls -v
Framework Core: 2.8.0 (local)
Plugin: 4.1.1
SDK: 2.3.2
Components: 3.2.3
ここからはこのプロジェクト内にインストールした serverless
を使っていきます。
serverlessが実行出来る事の確認
$ sls create
をした時点で、エンドポイントを叩くとサンプルのJSONが返ってくる参考用の hello
メソッドが用意されています。(細かい処理の流れの解説は省略)
import { APIGatewayProxyHandler } from 'aws-lambda'
import 'source-map-support/register'
export const hello: APIGatewayProxyHandler = async (event, _context) => {
return {
statusCode: 200,
body: JSON.stringify(
{
message: 'Go Serverless Webpack (Typescript) v1.0! Your function executed successfully!',
input: event,
},
null,
2
),
}
}
まずそのメソッドが使えるかの確認をしてみます。
メソッドを試すには $ sls invoke
コマンドを使用します。
# ローカルのsls invokeを使い hello メソッドを試す
$ npx sls invoke local --function hello
or
# --function は -f と省略する事が可能
$ npx sls invoke local -f hello
実行すると webpack
のバンドルが行われ、200のステータスコードが返ってくれば成功です!
$ npx sls invoke local -f hello
Serverless: Bundling with Webpack...
Time: 79ms
Built at: 10/17/2020 11:29:27 AM
Asset Size Chunks Chunk Names
handler.js 6.29 KiB handler [emitted] handler
Entrypoint handler = handler.js
[./handler.ts] 316 bytes {handler} [built]
[source-map-support/register] external "source-map-support/register" 42 bytes {handler} [built]
{
"statusCode": 200,
"body": "{\n \"message\": \"Go Serverless Webpack (Typescript) v1.0! Your function executed successfully!\",\n \"input\": \"\"\n}"
}
serverless invoke について
Serverless Frameworkで作成するメソッドは、
- エンドポイントを叩く
- cronで決めた時間に実行する
等、何かしらトリガーがあるはず、ですが、$ sls invoke
はそれらのメソッドをすぐに実行し試す事が出来ます。
もちろんローカルだけではなくデプロイしたものも実行出来ます。
デプロイしたものは $ sls invoke hello
とすればOK!
$ npx sls invoke --help
Plugin: Invoke
invoke ........................ Invoke a deployed function
invoke local .................. Invoke function locally
--function / -f (required) ......... The function name
--stage / -s ....................... Stage of the service
--region / -r ...................... Region of the service
--qualifier / -q ................... Version number or alias to invoke
--path / -p ........................ Path to JSON or YAML file holding input data
--type / -t ........................ Type of invocation
--log / -l ......................... Trigger logging data output
--data / -d ........................ Input data
--raw .............................. Flag to pass input data as a raw string
--app .............................. Dashboard app
--org .............................. Dashboard org
--config / -c ...................... Path to serverless config file
Prettierを導入(お好み)
Prettierを導入してルール決めしてしまえば、コーディングに集中しやすくなるので私はこの時点でPrettierを導入してます。
$ yarn add -D prettier
私の場合1人でプロジェクトを進める時はファイル数を増やしたくなくてPrettierの設定を基本的にpackage.jsonに書いてしまいますが、Prettierの設定内容や記載場所に関しては環境や好みに合わせて読み替えて下さい。
{
"name": "serverless-ts-sample",
・・・
"prettier": {
"singleQuote": true,
"semi": false,
"printWidth": 100,
"arrowParens": "avoid"
}
}
この時点だとPrettierを効かせたいファイルがルートのみなので以下のコマンドを実行します
$ npx prettier --write "./{*.ts,*.js}"
handler.ts 153ms
serverless.ts 10ms
webpack.config.js 35ms
serverless.ts → serverless.yml に
ここもお好みになってしまうのですが、 aws-nodejs-typescript
で作っているからなのか、最近の $ sls create
がそうなのかは分からないのですが、
Serverless Frameworkの設定ファイルが serverless.yml
ではなく serverless.ts
で作られます。
「.yml」ファイルか「.ts」ファイルの差ですが、ネット上に上がっている記事が「.yml」で書かれているものがほとんどで、
かつ以前にプラグインを入れようとして「.ts」だと詰まってしまった事があり、私的に serverless.yml
で書くのがおすすめです。
そのため serverless.yml
を追加し、 serverless.ts
を削除します。
serverless.ymlを追加
serverless.yml
の最小単位として以下のようになります
# 自身のサービス名を記載
service: serverless-ts-sample
# webpackでバンドルするため serverless-webpack は必須
plugins:
- serverless-webpack
# webpack.config.jsでexternalsを設定している場合、includeModules: true が必須
# 設定しないとデプロイ後に Runtime.ImportModuleError というエラーが起きる
custom:
webpack:
includeModules: true
# awsを使用する事を明記
# regionは使用したいリージョンを指定
# 日本の場合、東京リージョンの ap-northeast-1 を利用する事が多いはず
# runtimeには serverless.ts に書かれていたnodejsのバージョンを記載
provider:
name: aws
region: ap-northeast-1
runtime: nodejs12.x
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: get
serverless.tsを削除
「serverless.ts」ファイルを削除します。
ファイルを削除しても $ sls invoke
が実行出来る事を確認
$ npx sls invoke local -f hello
Serverless: Bundling with Webpack...
・・・
{
"statusCode": 200,
"body": "{\n \"message\": \"Go Serverless Webpack (Typescript) v1.0! Your function executed successfully!\",\n \"input\": \"\"\n}"
}
処理を追加
せっかくなので処理を追加してみます
Serverless Frameworkの処理流れは大きく以下のようになります。
- 1.serverless.yml に処理の設定を追加
- 何をトリガーとするか?例えばエンドポイントを指定したAPIアクセスなど
- その処理が呼ばれた時、実際の処理の呼び出し先の指定
- 2.実際の処理を追加
serverless.yml に処理の設定を追加
処理の追加は functions
の項目に行います。
サンプルとして書かれている hello
がとても分かりやすい!
functions:
# 処理の名前、invokeを使って呼び出す際に使用
hello:
# <ファイル名>.<そのファイル内のメソッド名>
handler: handler.hello
events:
- http:
# <エンドポイント>/helloで呼び出される
# 仮に別項目で独自ドメイン(ex: hogehoge.com)を指定しデプロイした場合、
# http://hogehoge.com/hello のようにして呼び出す事が可能
path: hello
method: get
↑を例に example
という項目を作成してみます
functions:
・・・
example:
handler: sample.example
events:
- http:
path: sample
method: get
実際の処理を追加
handler: sample.example
としたので「sample.ts」に example
メソッドを用意します
import { APIGatewayProxyHandler } from 'aws-lambda'
import 'source-map-support/register'
export const example: APIGatewayProxyHandler = async (_event, _context) => {
console.log(_context)
return {
statusCode: 200,
body: JSON.stringify(
{
message: 'hello Serverless Framework'
},
null,
2
),
}
}
console.log
をしておくと $sls invoke
した場合などに表示されます
ここで最終的にreturnしている値は APIGatewayProxyResult
として定義されています。
statusCode
と body
は必須なんですね
/**
* Works with Lambda Proxy Integration for Rest API or HTTP API integration Payload Format version 1.0
* @see - https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html
*/
export interface APIGatewayProxyResult {
statusCode: number;
headers?: {
[header: string]: boolean | number | string;
};
multiValueHeaders?: {
[header: string]: Array<boolean | number | string>;
};
body: string;
isBase64Encoded?: boolean;
}
追加したメソッドが使用出来るか試します
$ npx sls invoke local -f example
・・・
{
invokeid: 'id',
logGroupName: '/aws/lambda/serverless-ts-sample-dev-example',
logStreamName: '2015/09/22/[HEAD]13370a84ca4ed8b77c427af260',
functionVersion: 'HEAD',
isDefaultFunctionVersion: true,
functionName: 'serverless-ts-sample-dev-example',
memoryLimitInMB: '1024',
succeed: [Function: succeed],
fail: [Function: fail],
done: [Function: done],
getRemainingTimeInMillis: [Function: getRemainingTimeInMillis]
}
{
"statusCode": 200,
"body": "{\n \"message\": \"hello Serverless Framework\"\n}"
}
無事、200が返ってきました!
AWSにデプロイ&削除
最後にデプロイします。
Serverless Frameworkの何がすごい!てここまでもすごいけど、
デプロイもコマンド1個でデプロイ出来るんです!
1個ですよ!
$ npx sls deploy
すれば、APIGatewayやLambda、S3等色んなところに勝手にデプロイしてくれます!
なんだよ、神かよ、神なのかよ、、、
AWSにデプロイ
$sls deploy
は -v
( --verbose
)を付けると実行している内容の詳細が表示されるのでおすすめです。
$ npx sls deploy -v
{
"webpackConfig": "webpack.config.js",
"includeModules": false,
"packager": "npm",
"packagerOptions": {},
"keepOutputDirectory": false
}
・・・
・・・
CloudFormation - UPDATE_IN_PROGRESS - AWS::CloudFormation::Stack - serverless-ts-sample-dev
CloudFormation - CREATE_IN_PROGRESS - AWS::ApiGateway::RestApi - ApiGatewayRestApi
CloudFormation - CREATE_IN_PROGRESS - AWS::Logs::LogGroup - HelloLogGroup
CloudFormation - CREATE_IN_PROGRESS - AWS::IAM::Role - IamRoleLambdaExecution
CloudFormation - CREATE_IN_PROGRESS - AWS::Logs::LogGroup - ExampleLogGroup
CloudFormation - CREATE_IN_PROGRESS - AWS::ApiGateway::RestApi - ApiGatewayRestApi
CloudFormation - CREATE_COMPLETE - AWS::ApiGateway::RestApi - ApiGatewayRestApi
CloudFormation - CREATE_IN_PROGRESS - AWS::IAM::Role - IamRoleLambdaExecution
・・・
CloudFormation - CREATE_COMPLETE - AWS::ApiGateway::Resource - ApiGatewayResourceHello
CloudFormation - CREATE_COMPLETE - AWS::IAM::Role - IamRoleLambdaExecution
CloudFormation - CREATE_IN_PROGRESS - AWS::Lambda::Function - HelloLambdaFunction
CloudFormation - CREATE_IN_PROGRESS - AWS::Lambda::Function - ExampleLambdaFunction
・・・
・・・
Serverless: Stack update finished...
Service Information
service: serverless-ts-sample
stage: dev
region: ap-northeast-1
stack: serverless-ts-sample-dev
resources: 17
api keys:
None
endpoints:
GET - https://fghbzaelkd.execute-api.ap-northeast-1.amazonaws.com/dev/hello
GET - https://fghbzaelkd.execute-api.ap-northeast-1.amazonaws.com/dev/sample
functions:
hello: serverless-ts-sample-dev-hello
example: serverless-ts-sample-dev-example
layers:
None
無事デプロイ出来ました!
endpoints:
に試しで追加した sample
もあるのでアクセスしてみます。
まずchromeでエンドポイントにアクセス
続いて $sls invoke
$ npx sls invoke -f example
{
"statusCode": 200,
"body": "{\n \"message\": \"hello Serverless Framework\"\n}"
}
OKですね!
AWSから削除
削除もコマンド一発です!
ゴッソリきれいにしてくれます、何から何まですごいなぁ、ほんと。
こちらも同じく -v
を付けておくと何をやっているかが見られて安心感があります
$ npx sls remove -v
Serverless: Getting all objects in S3 bucket...
Serverless: Removing objects in S3 bucket...
Serverless: Removing Stack...
Serverless: Checking Stack removal progress...
CloudFormation - DELETE_IN_PROGRESS - AWS::CloudFormation::Stack - serverless-ts-sample-dev
・・・
Serverless: Stack removal finished...
これで削除も完了です!