非プロキシモードでAPI GatewayからPythonベースのAWS Lambdaメソッドを呼び出しています。例外の一部を使用してJSON本体とともに適切なHTTPステータスコードが設定されるように、例外を適切に処理する方法を教えてください。
例として、次のハンドラがあります。
def my_handler(event, context):
try:
s3conn.head_object(Bucket='my_bucket', Key='my_filename')
except botocore.exceptions.ClientError as e:
if e.response['Error']['Code'] == "404":
raise ClientException("Key '{}' not found".format(filename))
# or: return "Key '{}' not found".format(filename) ?
class ClientException(Exception):
pass
例外をスローするか、文字列を返す必要がありますか?次に、統合応答をどのように構成する必要がありますか?明らかに私はRTFMですが、FMはFUです。
Lambda、API Gateway、およびそれらがどのように連携するかについて、知っておくべきことがいくつかあります。
ハンドラ/関数/メソッドから例外がスローされると、例外はJSONメッセージにシリアル化されます。あなたのサンプルコードから、S3の404で、あなたのコードは以下をスローします:
_{
"stackTrace": [
[
"/var/task/mycode.py",
118,
"my_handler",
"raise ClientException(\"Key '{}' not found \".format(filename))"
]
],
"errorType": "ClientException",
"errorMessage": "Key 'my_filename' not found"
}
_
「統合応答」は、Lambdaからの応答をHTTPコードにマップします。また、通過するメッセージ本文を変更できます。
デフォルトでは、「200」統合応答が構成されています。これにより、シリアル化されたJSON例外を含め、Lambdaからのすべての応答がそのままHTTP 200(OK)応答としてクライアントに渡されます。
適切なメッセージの場合、「200」の統合応答を使用して、JSONペイロードを定義済みのモデルの1つにマッピングすることができます。
例外については、適切なHTTPステータスコードを設定し、おそらくスタックトレースを削除して、コードの内部を非表示にする必要があります。
返すHTTPステータスコードごとに、「統合応答」エントリを追加する必要があります。統合応答は、errorMessageと一致する正規表現一致(Java.util.regex.Matcher.matches()
ではなく.find()
を使用)で構成されていますフィールド。一致したら、ボディマッピングテンプレートを設定して、適切な例外ボディを選択的にフォーマットできます。
正規表現は例外からのerrorMessageフィールドに対してのみ一致するため、異なる統合応答が一致し、それに応じてエラーを設定します。 (_.*
_を使用してすべての例外と一致させることはできません。これは例外を除くすべての応答と一致するように見えるためです!)
メッセージに十分な詳細を含む例外を作成するには、 error-handling-patterns-in-Amazon-api-gateway-and-aws-lambda ブログでハンドラーに例外ハンドラーを作成して、例外メッセージで使用されるJSON文字列への例外の詳細。
私が好むアプローチは、API Gatewayへの応答を処理するハンドラーとして新しいtopメソッドを作成することです。このメソッドは、必要なペイロードを返すか、JSON文字列としてエンコードされた元の例外を例外メッセージとして例外をスローします。
_def my_handler_core(event, context):
try:
s3conn.head_object(Bucket='my_bucket', Key='my_filename')
...
return something
except botocore.exceptions.ClientError as e:
if e.response['Error']['Code'] == "404":
raise ClientException("Key '{}' not found".format(filename))
def my_handler(event=None, context=None):
try:
token = my_handler_core(event, context)
response = {
"response": token
}
# This is the happy path
return response
except Exception as e:
exception_type = e.__class__.__name__
exception_message = str(e)
api_exception_obj = {
"isError": True,
"type": exception_type,
"message": exception_message
}
# Create a JSON string
api_exception_json = json.dumps(api_exception_obj)
raise LambdaException(api_exception_json)
# Simple exception wrappers
class ClientException(Exception):
pass
class LambdaException(Exception):
pass
_
例外的に、Lambdaは次を返します:
_{
"stackTrace": [
[
"/var/task/mycode.py",
42,
"my_handler",
"raise LambdaException(api_exception_json)"
]
],
"errorType": "LambdaException",
"errorMessage": "{\"message\": \"Key 'my_filename' not found\", \"type\": \"ClientException\", \"isError\": true}"
}
_
errorMessageにすべての詳細が含まれているので、ステータスコードのマッピングを開始し、整形式のエラーペイロードを作成できます。 API GatewayはerrorMessageフィールドを解析およびエスケープ解除するため、使用される正規表現はエスケープを処理する必要はありません。
このClientExceptionを400エラーとしてキャッチし、ペイロードをクリーンなエラーモデルにマッピングするには、次のようにします。
新しいエラーモデルを作成します。
_{
"type": "object",
"title": "MyErrorModel",
"properties": {
"isError": {
"type": "boolean"
},
"message": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"token",
"isError",
"type"
]
}
_
400
_にマッピング400
_に設定します.*"type"\s*:\s*"ClientException".*
__application/json
_のボディマッピングテンプレートを追加して、errorMessage
のコンテンツをモデルにマッピングします。
_#set($inputRoot = $input.path('$'))
#set ($errorMessageObj = $util.parseJson($input.path('$.errorMessage')))
{
"isError" : true,
"message" : "$errorMessageObj.message",
"type": "$errorMessageObj.type"
}
_