Api Gateway request validation
api gatewayにはrequest validationという検証機能があります。もちろんapi gatewayに付けるlambda等でリクエストの検証をすることも可能ですが、lambdaにはビジネスロジックだけを含めたい、という場合には便利な機能です。
やり方
オフィシャルのserverless frameworkにはrequest validationのデプロイは含まれていないので、serverless-reqvalidator-plugin
とserverless-aws-documentation
を組み合わせてデプロイを実現します
最終的なコードをgitにuploadしています
https://github.com/five510/serverless-python-sample
a今回使ったplugin
https://github.com/deliveryhero/serverless-aws-documentation
https://www.npmjs.com/package/serverless-reqvalidator-plugin
今回は記事の登録をするapiを題材に、author
,contents
,title
実装をしてみます。
1. documentationとmodelを作成
serverless.ymlに以下のように記載
service: serverless-blog-api
plugins:
- serverless-reqvalidator-plugin
- serverless-aws-documentation
custom:
documentation:
api:
info:
version: '1.0.0'
title: Aritcle API
description: This is article API
tags:
-
name: Article
description: Article Management
models:
- name: articleModel
contentType: "application/json"
schema: ${file(model/article.json)}
model/article.jsonにjson schema形式で(https://json-schema.org/ )でmodelを記載
{
"title": "articleModel",
"type": "object",
"properties": {
"author": {
"type": "string"
},
"contents": {
"type": "string"
},
"title": {
"type": "string"
}
},
"required": ["author", "contents","title"]
}
2. serverless.yml内のResourceでRequestValidatorを作る
今回はrequest bodyの検証のみ有効にしています
resources:
Resources:
# APIG
ApiGatewayRestApi:
Type: AWS::ApiGateway::RestApi
Properties:
Name: article-api
# APIG Request Validation
onlyBody:
Type: "AWS::ApiGateway::RequestValidator"
Properties:
Name: 'only-body'
RestApiId:
Ref: ApiGatewayRestApi
ValidateRequestBody: true
ValidateRequestParameters: false
3. functionにrequestModelsとしてRequestValidatorをつける
serverless.ymlに以下のように記載
functions:
postArticle:
handler: handlers/article.put_article_handler
name: postArticle
memorySize: 1024
timeout: 300
events:
- http:
path: /article
method: post
integration: lambda-proxy
reqValidatorName: 'onlyBody'
cors:
origin: '*'
headers:
- Content-Type
- X-Amz-Date
- Authorization
- X-Api-Key
- X-Amz-Security-Token
- X-Amz-User-Agent
- Pragma
- Cache-Control
- If-Modified-Since
allowCredentials: true
documentation:
summary: "Post a article"
description: "Post a article"
requestModels:
"application/json": "articleModel"
4. 対応するlambdaのhandlerを書く
import json
def put_article_handler(event,context):
article_info = json.loads(event['body'])
author = article_info['author']
contents = article_info['contents']
title = article_info['title']
return {
"isBase64Encoded": True,
"statusCode": 200,
"headers": {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': 'true'
},
"body": json.dumps({'msg': 'ok'})
}
5. デプロイする
おなじみのやつ
sls deploy
validationが効いているか確認する
bodyに何も含めずテストをするとエラーが返ってくることが確認できます
テストどうするんだ問題
validationをlambda内部で持っている場合はhandlerに異常系のパラメーターを入れていたが、request validationを使う場合は異常系のテストはe2e testで補う必要がありそう。その場合はローカル開発環境でテストが完結しないのでstaging環境ありきの開発になる。微妙。