API Gateway で受信するデータを JSON Schema Validation でチェックしてから SQS へ送信する
概要
記事一覧はこちらです。
Using JSON Schema Validation with the AWS API Gateway という記事を見かけました。API Gateway で受信したメッセージを Lambda を呼び出す前に JSON Schema Validation で検証できるそうなので試してみます。Lambda を呼び出したら SQL へメッセージを送信し、別の Lambda でメッセージを受信します。
Serverless Framework の 1.8 から functions の events に sqs が記述できるようになるのですが、今回試した時のバージョンは 1.74 でしたので CloudWatch Events で 1分毎に Lambda を起動して SQS をチェックすることにします。
※(2020/07/05追記)何を見間違えてしまったのか SQS を events に設定できるのは 1.28 からでした。。。 今使用しているバージョンは 1.74 なので Using SQS with AWS Lambda and Serverless の記事通りに実装したらイベントベースで Lambda が呼び出されるようにできますね。
SQS への送信は serverless-apigateway-service-proxy プラグインを使用したかったのですが、このプラグインを使用して API Gateway の Endpoint を定義した時に JSON Schema Validation をセットする方法がないようだったので諦めました。
参照したサイト・書籍
Using JSON Schema Validation with the AWS API Gateway
https://fernandomc.com/posts/schema-validation-serverless-framework/API Gateway でリクエストの検証を有効にする
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-method-request-validation.htmlJSON Schema
https://json-schema.org/Getting Started Step-By-Step
https://json-schema.org/learn/getting-started-step-by-step.htmlUnderstanding JSON Schema
https://json-schema.org/understanding-json-schema/Enabling JSON5
https://www.jetbrains.com/help/idea/json.html#ws_json_choose_version知らないうちにJSON5 in Babel
https://qiita.com/jkr_2255/items/026e0fdb4570c88c4f51AWS::SQS::Queue
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.htmlAWS Lambda を Amazon SQS に使用する
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/with-sqs.htmlSending and receiving messages in Amazon SQS
https://boto3.amazonaws.com/v1/documentation/api/latest/guide/sqs-example-sending-receiving-msgs.htmlUsing SQS with AWS Lambda and Serverless
https://www.serverless.com/blog/aws-lambda-sqs-serverless-integration/Serverless updates - SQS events, private endpoints, Event Gateway open source
https://www.serverless.com/blog/serverless-updates-framework-v128/
目次
- jsonschema-sqs-project プロジェクトを作成する
- order_service サブプロジェクトを作成する
- 受信するメッセージのサンプルを作成する
- IntelliJ IDEA の .json を関連付ける File Type を JSON → JSON5 に変更する。。。が、API Gateway で JSON5 がサポートされていなかったので元に戻す
- JSON Schema Validation のための schema.json を作成する
- API Gateway 経由でメッセージを受信して SQS へ送信する Lambda を実装する
- SQS からメッセージを取り出してログに出力する Lambda を実装する
- serverless.yml を変更する
- deploy する
- 動作確認
- Validation エラーの時にどうやって原因を調べればよいのか?
手順
jsonschema-sqs-project プロジェクトを作成する
以下の手順で jsonschema-sqs-project プロジェクトを作成します。具体的な手順は IntelliJ IDEA+Node.js+npm+serverless framework+Python の組み合わせで開発環境を構築して AWS Lambda を作成してみる 参照。
- jsonschema-sqs-project の Empty Project を作成する。
- Python の仮想環境を作成する。
- Serverless Framework をローカルインストールする。
- .envrc を作成する。
pip install boto3
order_service サブプロジェクトを作成する
プロジェクトのルートディレクトリの下で npx sls create --template aws-python3 --path order_service
を実行して order_service サブプロジェクトを作成します。
受信するメッセージのサンプルを作成する
今回は以下のサンプルメッセージを受信します。細かい仕様は後で JSON Schema を作成する時に決めます。
{ "orderNumber": "1", "orderDate": "2020-06-27", "isGift": false, "orderedItem": [ { "orderItemNumber": "1001", "identifier": "book", "name": "サンプル書籍", "orderQuantity": 1, "price": 3800 }, { "orderItemNumber": "61059", "identifier": "furniture", "name": "テスト椅子", "orderQuantity": 2, "price": 12000 } ] }
IntelliJ IDEA の .json を関連付ける File Type を JSON → JSON5 に変更する。。。が、API Gateway で JSON5 がサポートされていなかったので元に戻す
IntelliJ IDEA で .json のファイルを編集すると "$schema": "http://json-schema.org/draft-04/schema#"
の定義を参照して自動補完してくれます(VSCode でも補完してくれましたので補完して当然のようです)。
schema を定義しておくと json の編集が便利になるんだなと思い IDEA のマニュアルで JSON を見にいくと、Enabling JSON5 という文字が。JSON5 って何?
調べてみると 知らないうちにJSON5 in Babel の記事を見つけました。JSON なのにケツカンマ有効でコメントが付けらたりできるとのこと。かなり前からあるのに全然知りませんでした。。。
Extend the JSON5 syntax to all JSON files に従い、.json を関連付ける File Type を JSON → JSON5 に変更してみます。
「Settings」ダイアログを開いて「Editor」-「File Types」の設定を確認すると、確かに今は「JSON」の File Type に .json が登録されています。
「JSON5」の「Registered patterns」で「+」ボタンをクリックして「Add Wildcard」ダイアログを表示してから *.json
を入力して「OK」ボタンをクリックします。
「Reassigned wildcard」ボタンをクリックします。
「JSON5」の File Type に .json が登録されますので「OK」ボタンをクリックしてダイアログを閉じます。
File Type が「JSON」の時は以下の画像のように赤波線が表示されていましたが、
「JSON5」に変更すると全て消えました!
すごいなと思いつつ API Gateway の JSON Schema Validation でも JSON5 がサポートされているのか別にサンプルプロジェクトを作って試してみたところ、JSON.parse(...)
が使われていてダメでした。。。 残念ですが、元に戻すことにします。
JSON5 を使いたい時には拡張子を .json5 にすればよいので覚えておくことにします。
JSON Schema Validation のための schema.json を作成する
order_service サブプロジェクトの下に schema.json を作成して、以下の内容を記述します。JSON Schema の定義で入れられそうなものは出来るだけ入れてみました。
{ "$schema": "http://json-schema.org/draft-04/schema#", "definitions": { "orderedItem": { "type": "object", "properties": { "orderItemNumber": { "type": "string", "pattern": "^[0-9]+$" }, "identifier": { "type": "string", "enum": [ "book", "furniture" ] }, "name": { "type": "string", "minLength": 1, "maxLength": 10 }, "orderQuantity": { "type": "integer", "minimum": 0, "maximum": 999 }, "price": { "type": "integer", "minimum": 0 } }, "required": [ "orderItemNumber", "identifier", "name", "orderQuantity", "price" ] } }, "title": "Order", "type": "object", "properties": { "orderNumber": { "type": "string", "pattern": "^[0-9]+$" }, "orderDate": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$" }, "isGift": { "type": "boolean" }, "orderedItem": { "type": "array", "minItems": 1, "maxItems": 3, "uniqueItems": true, "items": { "$ref": "#/definitions/orderedItem" } } }, "required": [ "orderNumber", "orderDate", "orderedItem" ] }
API Gateway 経由でメッセージを受信して SQS へ送信する Lambda を実装する
order_service/handler.py のファイル名を apigw_handler.py に変更し、以下の内容に変更します。
import json import logging import os import boto3 logger = logging.getLogger() logger.setLevel(logging.INFO) def send_msg(event, context): sqs_client = boto3.client('sqs') logger.info(event['body']) response = sqs_client.send_message( QueueUrl=os.environ['QUEUE_URL'], MessageBody=event['body'] ) body = { "message": f"send message to sqs, MessageId = {response['MessageId']}", "input": event } response = { "statusCode": 200, "body": json.dumps(body) } return response
SQS からメッセージを取り出してログに出力する Lambda を実装する
order_service ディレクトリの下に sqs_handler.py を作成し、以下の内容を記述します。
import logging import os import boto3 logger = logging.getLogger() logger.setLevel(logging.INFO) def recv_msg(event, context): sqs_client = boto3.client('sqs') response = sqs_client.receive_message(QueueUrl=os.environ['QUEUE_URL']) if 'Messages' in response: logger.info(response) for msg in response['Messages']: sqs_client.delete_message(QueueUrl=os.environ['QUEUE_URL'], ReceiptHandle=msg['ReceiptHandle'])
serverless.yml を変更する
order_service/serverless.yml を以下の内容に変更します。
service: order-service custom: queueName: "SampleQueue" provider: name: aws runtime: python3.8 stage: dev region: ap-northeast-1 iamRoleStatements: - Effect: "Allow" Action: - "sqs:*" Resource: - Fn::GetAtt: [ SampleQueue, Arn ] functions: sendMsg: handler: apigw_handler.send_msg environment: QUEUE_URL: !Ref SampleQueue events: - http: path: send-msg method: post cors: true request: schema: application/json: ${file(schema.json)} recvMsg: handler: sqs_handler.recv_msg environment: QUEUE_URL: !Ref SampleQueue events: - schedule: rate(1 minute) resources: Resources: SampleQueue: Type: AWS::SQS::Queue Properties: QueueName: "${self:custom.queueName}"
deploy する
deploy します。
動作確認
Postman から endpoint へ上に書いたサンプルメッセージを送信すると 200 OK が返ってきました。
ログにも送受信されたメッセージが出力されています。
JSON Schema の定義に合わないメッセージ(orderedItem の要素数が minItems 未満)を送信すると 400 Bad Request が返ってきました。
Validation エラーの時にどうやって原因を調べればよいのか?
1つ目は送信しているメッセージを適当なファイルに保存してから、IntelliJ IDEA のエディタ上で JSON Schema を適用してエラー箇所を表示させる方法です。
ファイルに保存してから画面右下の「No JSON schema」をクリックします。
メニューが表示されるので、一番上の「New Schema Mapping...」を選択します。
「JSON Schema Mappings」ダイアログが表示されるので、「Schema file or URL」に上で作成した schema.json を選択してから「OK」ボタンをクリックします。
ファイルに保存したメッセージを変更して JSON Schema に合わないようにするとその箇所が分かるように表示されます。
もっと詳細な内容を知りたい場合には、エディタ上でコンテキストメニューを表示させて「Analyze」-「Inspect Code...」を選択した後、
「Specify Inspection Code」ダイアログが表示されるので、何も変更せずに「OK」ボタンをクリックします。
そうすると画面下に Inspection Results Window が表示されて、そこに詳細なエラー内容が表示されます。
2つ目は AWS マネジメントコンソールの API Gateway の画面からテスト送信してログを表示させる方法です。
今回作成された API Gateway の「リソース」の画面に遷移してから、登録した endpoint の POST メソッドの画面の「テスト」リンクをクリックします。
メソッドテストの画面が表示されるので「リクエスト本文」に送信する JSON を記述して「テスト」ボタンをクリックします。
そうすると画面の「ログ」にエラーの内容が表示されます。ただしこの方法だと最初のエラーしか表示されないようです。
最後に npx sls remove -v
を実行して構築した環境を削除します。
履歴
2020/06/28
初版発行。
2020/07/05
概要に "※(2020/07/05追記)..." の記述を追加しました。