Serverless Framework が0の時代にいくつか触ってたんだけど、1になって全然変わっちゃったのでしばらく遠ざかってました。
久しぶりに触ってみたら、0系からの簡易なマイグレーションは難しそうけど、過去のチラ見しつつ作り直しても手間じゃないんじゃないか、と思うほど設定が簡単になっていたので、いくつか自分のやりたいことを中心に気づいたことまとめ。
プロジェクト(サービス?)作成
以前のServerlessにあった"project"という概念はなくなっているので、プロジェクトと表現するのが適切かはよくわからないけど...
後で書くように設定ファイルの中では、"service"という言葉が使われているので、それを使うべきなのかもしれない。
$ sls create --template aws-nodejs --path slstest
Serverless: Generating boilerplate...
Serverless: Generating boilerplate in "/Users/user/github/slstest"
_______ __
| _ .-----.----.--.--.-----.----| .-----.-----.-----.
| |___| -__| _| | | -__| _| | -__|__ --|__ --|
|____ |_____|__| \___/|_____|__| |__|_____|_____|_____|
| | | The Serverless Application Framework
| | serverless.com, v1.3.0
-------'
Serverless: Successfully generated boilerplate for template: "aws-nodejs"
こんな感じで実行してやると、以下の構成が作られる。
$ tree slstest
slstest
├── handler.js
└── serverless.yml
0 directories, 2 files
シンプルすぎるやろ! 必死で覚えた以前の複雑さどこに消えた!
serverless.ymlの中身はこんな感じ(コメントアウト削除)。
service: slstest
provider:
name: aws
runtime: nodejs4.3
functions:
hello:
handler: handler.hello
handler.jsの中身はこう。
'use strict';
module.exports.hello = (event, context, callback) => {
const response = {
statusCode: 200,
body: JSON.stringify({
message: 'Go Serverless v1.0! Your function executed successfully!',
input: event,
}),
};
callback(null, response);
};
この状態で、
$ sls deploy
を実行すると、lambdaに "slstest-dev-hello"ファンクションが作られます。
ファンクションの中身は、handler.jsの中の、hello関数が定義されます。
が、これだけだとWebから叩いて実行はできません。
これだけだとlambdaしか定義されておらず、API Gatewayが定義されていないからです。
API Gatewayを定義するには、functionの中のevents設定を使います。
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: get
これで"sls deploy"を行うと、API Gatewayにdev-dldtest APIが作成され、その下にリソース/helloのメソッドGETが作成され、それが"slstest-dev-hello"ファンクションに紐づけられます。
APIを増やす
単純に、jsファイルを増やしてやって、serverless.ymlでそれのlambdaやAPI Gatewayへの紐づけ方を定義してやればOK。
例えば、handler.jsをコピペしたhamdler2.jsを作ってやって、それをGET /hello2に紐づけたいなら、
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: get
hello2:
handler: handler2.hello
events:
- http:
path: hello2
method: get
で動きます。
クエリストリングの取得
Serverless 0系の場合はあれほどs-template.ymlあたりをハックしてやらないとクエリストリングを取るのすら苦労してたのが嘘のようなのですが、Serverless 1系では普通にクエリストリングがパースされてくるようです。
テンプレートから作られたhandler.jsの記述を見ると、
module.exports.hello = (event, context, callback) => {
...
};
この"event"の、event.input.queryStringParametersからパースされた値が取れるようです。
PathInfoの取得
さすがにPathInfoの取得は、API Gatewayに対応したリソースの追加がいるので指定しておかないと読み込めません。
設定は、serverless.ymlで、以下のような感じ。
functions:
hello:
handler: handler.hello
events:
- http:
path: hello/{x}/{y}
method: get
integration: lambda
request:
parameters:
paths:
x: true
y: true
これで、PathInfoの情報が分解されて、event.input.pathにオブジェクトとして入ってきます。
キモというか、気をつけないといけないのは、"integration: lambda"という一節です。
lambda-proxy integrationとlambda integration
これは、API Gatewayとlambdaの間の紐付け時の中間処理(integration)を、"lambda-proxy"形式ではなく"lambda"形式で行うという宣言です。
両者の違いは、"lambda-proxy"形式がhttpに特有な処理をより「よしなに」やってくれる感じで、"lambda"形式がより生に近いものを操作できる感じです。
Pathinfoを読むためには"lambda"形式を指定しないといけないのですが、その副作用?として、まず入力で"lambda-proxy"形式だとevent.input.queryStringParametersに入ってくるクエリストリングが、"lambda"形式だとevent.input.queryに入ってきます。
また、自動生成されるhandler.jsに、
// Use this code if you don't use the http event with the LAMBDA-PROXY integration
// callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event });
と書かれているように、"lambda"形式だと、callbackの引数にはstringではなくobjectを返す必要があるようです。
追加モジュールなどのアップロード
これは、serviceのフォルダ内にサブフォルダ(node_modules以外も含め)などを設定しておくと、一緒にパッケージングして送ってくれるようで、フォルダ外のものを選択的に追加したり、内のものを選択的に除外したりは動かないようです。
テンプレート生成のserverless.ymlに、
# you can add packaging information here
#package:
# include:
# - include-me.js
# - include-me-dir/**
# exclude:
# - exclude-me.js
# - exclude-me-dir/**
とあるので、この辺をいじってやれば制御できるのかなと思いましたが、特に何も変わりませんでした。
将来的に導入されるのかもしれません。
駆け足でとりとめもなかったですが、Serverless 1系を触ってみて、触ってみた範囲で0系と違うところのまとめでした。