【AWS】【Serverless Framework 入門】 API Gateway + Lambda + DynamoDB サンプル
はじめに
こちらの記事の続編になります。
前回は Serverless Framework を使って hello 関数を Lambda にデプロイしたところまで行いました。
(Lambda をただデプロイできれば前編の記事は見なくても全然大丈夫です。)
今回はそれを API Gateway 経由で API として公開し、さらに DynamoDB との疎通にも試みるものになります。
以下の Serverless Framework の公式サンプルを参考にしました。
できたこと
以下の図の環境を Serverless Framework で構築しました。
ソースは GitHub に公開したのでそちらを参照してください。
公式サンプルの「AWS | REST API With DynamoDB」 とほとんど同じように実装しました。
一気に解説すると大変なので以下の手順に分けて見ていきたいと思います。
- API の公開(練習)
- DynamoDB のテーブル作成
- API の公開と DynamoDB との疎通
1. API の公開(練習)
以下の公式サンプルを参考にしました。
・AWS | REST API Example
hello 関数を GET メソッドの API として公開してみたいと思います。
serverless.yml の変更
serverless.yml
に https リクエストのイベントを追加します。
functions:
hello:
handler: handler.hello
+ events:
+ - http:
+ path: hello
+ method: get
デプロイ
変更後にデプロイしてみます。
$ sls deploy -v
(省略)
Serverless: Stack update finished...
Service Information
service: hogehoge
stage: dev
region: us-east-1
stack: hogehoge-dev
resources: 11
api keys:
None
endpoints:
GET - https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/hello
functions:
hello: hogehoge-dev-hello
layers:
None
Stack Outputs
HelloLambdaFunctionQualifiedArn: arn:aws:lambda:us-east-1:xxxxxxxxx:function:hogehoge-dev-hello:5
ServiceEndpoint: https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev
ServerlessDeploymentBucketName: hogehoge-dev-serverlessdeploymentbucket-1q2qo8ezm7dcf
https リクエストのイベントを追加したことによって、こちらのエンドポイントが開放されます。
endpoints:
GET - https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/hello
API の疎通確認
curl で叩いてみます。
$ curl https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/hello
{
"message": "Go Serverless v1.0! Your function executed successfully!",
"input": {
"resource": "/hello",
(省略)
}
}
レスポンスが返ってくることが確認できました。API の公開の成功です。
AWS コンソールの確認
AWS コンソールの API Gateway を確認してみます。
このように API が登録されていることがわかります。
ちなみに serverless.yml
に events.http.path
を記述しないと API Gateway には何も登録されません。
以上で API を公開する方法はわかりました。
2. DynamoDB のテーブル作成
以下の公式サンプルを参考にしました。
・ AWS | REST API With DynamoDB
こちらのサンプルの DynamoDB のテーブル作成だけを抜き出したものになります。
serverless.yml の変更
provider:
name: aws
runtime: nodejs12.x
+ environment:
+ DYNAMODB_TABLE: ${self:service}-${opt:stage, self:provider.stage}
+ iamRoleStatements:
+ - Effect: Allow
+ Action:
+ - dynamodb:Query
+ - dynamodb:Scan
+ - dynamodb:GetItem
+ - dynamodb:PutItem
+ - dynamodb:UpdateItem
+ - dynamodb:DeleteItem
+ Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}"
(省略)
+resources:
+ Resources:
+ TodosDynamoDbTable:
+ Type: 'AWS::DynamoDB::Table'
+# DeletionPolicy: Retain
+ Properties:
+ AttributeDefinitions:
+ -
+ AttributeName: id
+ AttributeType: S
+ KeySchema:
+ -
+ AttributeName: id
+ KeyType: HASH
+ ProvisionedThroughput:
+ ReadCapacityUnits: 1
+ WriteCapacityUnits: 1
+ TableName: ${self:provider.environment.DYNAMODB_TABLE}
provider
と resources
に分けて簡単に解説します。
provider
provider
には共通で用いる環境変数の設定や Lambda から他のリソースに関する IAM ロールなどを設定します。
provider:
name: aws
runtime: nodejs12.x
environment:
DYNAMODB_TABLE: ${self:service}-${opt:stage, self:provider.stage}
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}"
-
opt:xxx
- コマンドライン引数にアクセスできます。例えばコマンドラインで
sls deploy --stage prd
と実行した場合は ${opt:stage} = prd となります。
- コマンドライン引数にアクセスできます。例えばコマンドラインで
-
self:xxx
- この記法で自身の serverless.yml で定義している key にアクセスできます。
-
${opt:xxx, self:xxx}
-
opt:xxx
が定義されていればその値を優先し、もし、定義されていないければself:xxx
の値を使用する書き方です。
-
-
environment
- 環境変数を定義します。今回はここにデーブル名を定義します。
-
iamRoleStatements
- 実行時に他の AWS リソースを参照する場合にここで Lambda の IAM ロールを設定します。今回は DynamoDB へのアクセス許可を追加しています。
-
Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:table/${self:provider.environment.DYNAMODB_TABLE}"
- 設定した IAM ロールはここの項目で設定したリソースに対して有効になります。DynamoDB の特定のテーブルに対して有効にする場合このようになります。ちなみに
${self:provider.environment.DYNAMODB_TABLE}
は上記で解説しているようにenvironment
で定義しているDYNAMODB_TABLE
の値になります。
- 設定した IAM ロールはここの項目で設定したリソースに対して有効になります。DynamoDB の特定のテーブルに対して有効にする場合このようになります。ちなみに
resources
resources
には AWS リソースの設定事項を記述します。
今回は DynamoDB のテーブル定義を記述していきます。
resources:
Resources:
TodosDynamoDbTable:
Type: 'AWS::DynamoDB::Table'
# DeletionPolicy: Retain
Properties:
AttributeDefinitions:
-
AttributeName: id
AttributeType: S
KeySchema:
-
AttributeName: id
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
TableName: ${self:provider.environment.DYNAMODB_TABLE}
-
TodosDynamoDbTable
- ここはリソースの論理 ID です。一意であれば任意の値で大丈夫です。
-
DeletionPolicy: Retain
- リソースの削除ポリシーの設定ができます。
Delete
(デフォルト),Retain
,Snapshot
のいずれか 3 つの設定が可能です。スタックが削除されてもテーブルを保持する場合はRetain
を採用しますが、今回はスタックが削除されたタイミング(sls remove -v
)でテーブルも削除してほしいので、何も記述せずにデフォルトのDelete
設定とします。(公式ドキュメント)
- リソースの削除ポリシーの設定ができます。
-
AttributeDefinitions
,KeySchema
,ProvisionedThroughput
- このあたりの設定は DynamoDB そのものに関わる設定のため今回は説明を省略いたします。ここではテーブルには
id
という項目を設けましたよ、スループット(1 秒あたりの読み込み/書き込み数)は 1 にしますよ、ということぐらいで十分です。(AWS DynamoDB スループットの設定が料金に跳ねるので注意)
- このあたりの設定は DynamoDB そのものに関わる設定のため今回は説明を省略いたします。ここではテーブルには
-
TableName
- テーブル名です。今回は provider の environment で
DYNAMODB_TABLE
は${self:service}-${opt:stage, self:provider.stage}
= hogehoge-dev と設定していることになります。詳しくは provider の設定を確認してください。
- テーブル名です。今回は provider の environment で
デプロイ
serverless.yml を更新したらデプロイします。
$ sls deploy -v
(省略)
AWS コンソールの確認
テーブルが作成されているはずなので AWS コンソールで DynamoDB のサービスを開いてみます。
hogehoge-dev テーブルが作成されていることがわかります。
また、provider.iamRoleStatements で IAM ロールを設定しているので、CWL も確認してみます。
hogehoge-dev テーブルに読み込み/書き込み権限がついていることがわかります。
これで DynamoDB のテーブル作成ができるようになりました。
3. API の公開と DynamoDB との疎通
こちらの環境を構築していきます。
インターフェース設計
以下の API を作成したいと思います。
やりたいこと | path | method | data(request body parameter) | DynamoDB の操作 | 用意する関数名 |
---|---|---|---|---|---|
全件取得 | /todos | GET | なし | Scan | list |
単一取得 | /todos/{id} | GET | なし | GetItem | get |
追加 | /todos | POST | あり | PutItem | create |
更新 | /todos/{id} | PUT | あり | UpdateItem | update |
削除 | /todos/{id} | DELETE | なし | DeleteItem | delete |
serverless.yml の変更
設計したインターフェースを serverless.yml に反映させます。
path
と method
をこれから実装するであろう JavaScript ファイルとそこに定義する関数(handler
)に結びつけるように書くだけです。
functions:
- http:
path: hello
method: get
+
+ list:
+ handler: todos/list.list
+ events:
+ - http:
+ path: todos
+ method: get
+ cors: true
+
+ get:
+ handler: todos/get.get
+ events:
+ - http:
+ path: todos/{id}
+ method: get
+ cors: true
+
+ create:
+ handler: todos/create.create
+ events:
+ - http:
+ path: todos
+ method: post
+ cors: true
+
+ update:
+ handler: todos/update.update
+ events:
+ - http:
+ path: todos/{id}
+ method: put
+ cors: true
+
+ delete:
+ handler: todos/delete.delete
+ events:
+ - http:
+ path: todos/{id}
+ method: delete
+ cors: true
必要な npm パッケージのインストール
テーブルへのアイテムの追加の処理時にユニークな id を払い出すのに npm の uuid
というパッケージを使うので packeage.json を作成して登録します。
$ npm init -y
$ npm install uuid
{
(省略)
"dependencies": {
"uuid": "^8.3.1"
}
}
内部処理の実装
詳しい実装は GitHub に公開したのでそちらを参照してください。
公式サンプルの「AWS | REST API With DynamoDB」 と全く同じように実装しました。
デプロイ
デプロイしてみます。
$ sls deploy -v
(省略)
Serverless: Stack update finished...
Service Information
service: hogehoge
stage: dev
region: us-east-1
stack: hogehoge-dev
resources: 41
api keys:
None
endpoints:
GET - https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/hello
GET - https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/todos
GET - https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/todos/{id}
POST - https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/todos
PUT - https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/todos/{id}
DELETE - https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/todos/{id}
functions:
hello: hogehoge-dev-hello
list: hogehoge-dev-list
get: hogehoge-dev-get
create: hogehoge-dev-create
update: hogehoge-dev-update
delete: hogehoge-dev-delete
layers:
None
(省略)
以下のようにインターフェース設計どおりに API が公開されたようです。
endpoints:
GET - https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/hello
GET - https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/todos
GET - https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/todos/{id}
POST - https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/todos
PUT - https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/todos/{id}
DELETE - https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/todos/{id}
API の疎通確認
curl コマンドを叩いて API を呼び出してもいいのですが、Postman の方がいろいろわかりやすいので、Postman から確認してみます。
アイテムを POST メソッドを呼んで追加してみます。
うまく行っているみたいですね。
今度は GET で Scan してみます。
ちゃんと取得できました。
AWS コンソールの確認
この結果を AWS の DynamoDB からも確認してみます。
ちゃんと反映されているみたいですね。
これでやりたいことができました。
リソースの削除
リソースを削除するまでが Serverless Framework です。
$ sls remove -v
(省略)
一応、念のため AWS コンソールを見に行って削除されていることは確認した方がいいです。
リソースを削除してもすぐにデプロイできるので、本当に気軽に削除できますね。
まとめ
Serverless Framework を使って、以下のことができるようになりました。
- API の公開
- 環境変数の設定
- IAM ロールの設定
- DynamoDB のテーブル定義の設定
- インターフェースの定義の設定
- API と DynamoDB の疎通
その結果、以下の図のような環境を Serverless Framework で構築することができました。
【続編はこちら】
・【Serverless Framework】カスタムドメイン設定方法(開発環境と本番環境の分離も考慮)
Discussion