in samcli/local/apigw/local_apigw_service.py [0:0]
def _parse_v1_payload_format_lambda_output(lambda_output: str, binary_types, flask_request, event_type):
"""
Parses the output from the Lambda Container
:param str lambda_output: Output from Lambda Invoke
:param binary_types: list of binary types
:param flask_request: flash request object
:param event_type: determines the route event type
:return: Tuple(int, dict, str, bool)
"""
# pylint: disable-msg=too-many-statements
try:
json_output = json.loads(lambda_output)
except ValueError as ex:
raise LambdaResponseParseException("Lambda response must be valid json") from ex
if not isinstance(json_output, dict):
raise LambdaResponseParseException(f"Lambda returned {type(json_output)} instead of dict")
if event_type == Route.HTTP and json_output.get("statusCode") is None:
raise LambdaResponseParseException(f"Invalid API Gateway Response Key: statusCode is not in {json_output}")
status_code = json_output.get("statusCode") or 200
headers = LocalApigwService._merge_response_headers(
json_output.get("headers") or {}, json_output.get("multiValueHeaders") or {}
)
body = json_output.get("body")
if body is None:
LOG.warning("Lambda returned empty body!")
is_base_64_encoded = LocalApigwService.get_base_64_encoded(event_type, json_output)
try:
status_code = int(status_code)
if status_code <= 0:
raise ValueError
except ValueError as ex:
raise LambdaResponseParseException("statusCode must be a positive int") from ex
try:
if body:
body = str(body)
except ValueError as ex:
raise LambdaResponseParseException(
f"Non null response bodies should be able to convert to string: {body}"
) from ex
invalid_keys = LocalApigwService._invalid_apig_response_keys(json_output, event_type)
# HTTP API Gateway just skip the non allowed lambda response fields, but Rest API gateway fail on
# the non allowed fields
if event_type == Route.API and invalid_keys:
raise LambdaResponseParseException(f"Invalid API Gateway Response Keys: {invalid_keys} in {json_output}")
# If the customer doesn't define Content-Type default to application/json
if "Content-Type" not in headers:
LOG.info("No Content-Type given. Defaulting to 'application/json'.")
headers["Content-Type"] = "application/json"
try:
# HTTP API Gateway always decode the lambda response only if isBase64Encoded field in response is True
# regardless the response content-type
# Rest API Gateway depends on the response content-type and the API configured BinaryMediaTypes to decide
# if it will decode the response or not
if (event_type == Route.HTTP and is_base_64_encoded) or (
event_type == Route.API
and LocalApigwService._should_base64_decode_body(
binary_types, flask_request, headers, is_base_64_encoded
)
):
body = base64.b64decode(body)
except ValueError as ex:
LambdaResponseParseException(str(ex))
return status_code, headers, body