題材とするアーキテクチャ
API Gatewayの返り値を整形する。
エラー時に400/500台のステータスコードを付してDescriptionをつけて返したい。
1 Exceptionクラスを継承して拡張した例外クラスを作る。
2 エラー時にraiseする。
Lambda(1)
import json
import boto3
import logging
import traceback
logger = logging.getLogger()
logger.setLevel(logging.INFO)
dynamodb = boto3.resource('dynamodb')
# 例外クラスを拡張
class ExtendException(Exception):
def __init__(self, statusCode, description):
self.statusCode = statusCode
self.description = description
def __str__(self):
obj = {
"statusCode": self.statusCode,
"description": self.description
}
return json.dumps(obj)
def lambda_handler(event, context):
# validation check
if not "key" in event or not isinstance(event["key"], int):
raise ExtendException(400, "Bad Request")
# 何らかの処理
return 0
テスト
response
{
"errorMessage": "{\"statusCode\": 400, \"description\": \"Bad Request\"}",
"errorType": "ExtendException",
"stackTrace": [
" File \"/var/task/lambda_function.py\", line 29, in lambda_handler\n raise ExtendException(400, \"Bad Request\")\n"
]
}
3 API Gatewayのレスポンスをマッピング
Lambdaエラーの正規表現では.*statusCode: 400,.*
を指定。
Lambdaから返されるエラーレスポンスのerrorMessage
の部分のみ返している。
テスト
response
{
"statusCode": 400,
"description": "Bad Request"
}
別Lambdaからコールした時にエラー内容を表示する。
以下のようにしてエラーレスポンスを拾うことができる。
try:
pass
except urllib.error.HTTPError as err:
res = err.read().decode("utf-8")
Lambda(2)
import json
import urllib.request, urllib.error
import logging
import traceback
logger = logging.getLogger()
logger.setLevel(logging.INFO)
class ExtendException(Exception):
def __init__(self, statusCode, description):
self.statusCode = statusCode
self.description = description
def __str__(self):
obj = {
"statusCode": self.statusCode,
"description": self.description
}
return json.dumps(obj)
request_url = "https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/v1"
api_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
def lambda_handler(event, context):
try:
headers = {'x-api-key': api_key, "Content-Type":"application/json"}
method = "POST"
# validation errorするようにAPIをコールする。
request_json = {
"notExistKey": 1
}
req = urllib.request.Request(url=request_url, method=method, headers=headers, data=json.dumps(request_json).encode())
with urllib.request.urlopen(req) as res:
body = res.read().decode("utf-8")
except urllib.error.HTTPError as err:
traceback.print_exc()
res = err.read().decode("utf-8")
res = json.loads(res)
logger.info("------------------")
logger.info(res)
logger.info("------------------")
raise ExtendException(500, "[ERROR] {} : {}".format(res["statusCode"], res["description"]))
except urllib.error.URLError as err:
traceback.print_exc()
res = err.read().decode("utf-8")
res = json.loads(res)
logger.info("------------------")
logger.info(res)
logger.info("------------------")
raise ExtendException(500, "[ERROR] {} : {}".format(res["statusCode"], res["description"]))
except:
traceback.print_exc()
raise ExtendException(500, "Internal Error")
return json.loads(body)
テスト
response
{
"errorMessage": "{\"statusCode\": 500, \"description\": \"[ERROR] 400 : Bad Request\"}",
"errorType": "ExtendException",
"stackTrace": [
" File \"/var/task/lambda_function.py\", line 45, in lambda_handler\n raise ExtendException(500, \"[ERROR] {} : {}\".format(res[\"statusCode\"], res[\"description\"]))\n"
]
}
追記 2020/08/06
Lambdaのタイムアウトをハンドリングする。
上記の設定ではLambda(1)でタイムアウトした際にステータスコード200が返ってしまう。
{
"errorMessage": "2020-08-06T13:36:57.311Z 312a1819-af1a-4fc5-bb9c-f8ed8f573a9b Task timed out after 3.00 seconds"
}
統合レスポンスの正規表現では以下のように指定することでLambdaのタイムアウトをハンドリングできる。
.*"statusCode": 500,.*|.*Task timed out after.*