Handle Lambda errors in API Gateway - Amazon API Gateway

Handle Lambda errors in API Gateway

For Lambda custom integrations, you must map errors returned by Lambda in the integration response to standard HTTP error responses for your clients. Otherwise, Lambda errors are returned as 200 OK responses by default and the result is not intuitive for your API users.

There are two types of errors that Lambda can return: standard errors and custom errors. In your API, you must handle these differently.

With the Lambda proxy integration, Lambda is required to return an output of the following format:

{ "isBase64Encoded" : "boolean", "statusCode": "number", "headers": { ... }, "body": "JSON string" }

In this output, statusCode is typically 4XX for a client error and 5XX for a server error. API Gateway handles these errors by mapping the Lambda error to an HTTP error response, according to the specified statusCode. For API Gateway to pass the error type (for example, InvalidParameterException), as part of the response to the client, the Lambda function must include a header (for example, "X-Amzn-ErrorType":"InvalidParameterException") in the headers property.

Handle standard Lambda errors in API Gateway

A standard AWS Lambda error has the following format:

{ "errorMessage": "<replaceable>string</replaceable>", "errorType": "<replaceable>string</replaceable>", "stackTrace": [ "<replaceable>string</replaceable>", ... ] }

Here, errorMessage is a string expression of the error. The errorType is a language-dependent error or exception type. The stackTrace is a list of string expressions showing the stack trace leading to the occurrence of the error.

For example, consider the following JavaScript (Node.js) Lambda function.

export const handler = function(event, context, callback) { callback(new Error("Malformed input ...")); };

This function returns the following standard Lambda error, containing Malformed input ... as the error message:

{ "errorMessage": "Malformed input ...", "errorType": "Error", "stackTrace": [ "export const handler (/var/task/index.js:3:14)" ] }

Similarly, consider the following Python Lambda function, which raises an Exception with the same Malformed input ... error message.

def lambda_handler(event, context): raise Exception('Malformed input ...')

This function returns the following standard Lambda error:

{ "stackTrace": [ [ "/var/task/lambda_function.py", 3, "lambda_handler", "raise Exception('Malformed input ...')" ] ], "errorType": "Exception", "errorMessage": "Malformed input ..." }

Note that the errorType and stackTrace property values are language-dependent. The standard error also applies to any error object that is an extension of the Error object or a subclass of the Exception class.

To map the standard Lambda error to a method response, you must first decide on an HTTP status code for a given Lambda error. You then set a regular expression pattern on the selectionPattern property of the IntegrationResponse associated with the given HTTP status code. In the API Gateway console, this selectionPattern is denoted as Lambda error regex in the Integration response section, under each integration response.

Note

API Gateway uses Java pattern-style regexes for response mapping. For more information, see Pattern in the Oracle documentation.

For example, to set up a new selectionPattern expression, using AWS CLI, call the following put-integration-response command:

aws apigateway put-integration-response --rest-api-id z0vprf0mdh --resource-id x3o5ih --http-method GET --status-code 400 --selection-pattern "Malformed.*" --region us-west-2

Make sure that you also set up the corresponding error code (400) on the method response. Otherwise, API Gateway throws an invalid configuration error response at runtime.

Note

At runtime, API Gateway matches the Lambda error's errorMessage against the pattern of the regular expression on the selectionPattern property. If there is a match, API Gateway returns the Lambda error as an HTTP response of the corresponding HTTP status code. If there is no match, API Gateway returns the error as a default response or throws an invalid configuration exception if no default response is configured.

Setting the selectionPattern value to .* for a given response amounts to resetting this response as the default response. This is because such a selection pattern will match all error messages, including null, i.e., any unspecified error message. The resulting mapping overrides the default mapping.

To update an existing selectionPattern value using the AWS CLI, call the update-integration-response operation to replace the /selectionPattern path value with the specified regex expression of the Malformed* pattern.

To set the selectionPattern expression using the API Gateway console, enter the expression in the Lambda error regex text box when setting up or updating an integration response of a specified HTTP status code.

Handle custom Lambda errors in API Gateway

Instead of the standard error described in the preceding section, AWS Lambda allows you to return a custom error object as JSON string. The error can be any valid JSON object. For example, the following JavaScript (Node.js) Lambda function returns a custom error:

export const handler = (event, context, callback) => { ... // Error caught here: var myErrorObj = { errorType : "InternalServerError", httpStatus : 500, requestId : context.awsRequestId, trace : { "function": "abc()", "line": 123, "file": "abc.js" } } callback(JSON.stringify(myErrorObj)); };

You must turn the myErrorObj object into a JSON string before calling callback to exit the function. Otherwise, the myErrorObj is returned as a string of "[object Object]". When a method of your API is integrated with the preceding Lambda function, API Gateway receives an integration response with the following payload:

{ "errorMessage": "{\"errorType\":\"InternalServerError\",\"httpStatus\":500,\"requestId\":\"e5849002-39a0-11e7-a419-5bb5807c9fb2\",\"trace\":{\"function\":\"abc()\",\"line\":123,\"file\":\"abc.js\"}}" }

As with any integration response, you can pass through this error response as-is to the method response. Or you can have a mapping template to transform the payload into a different format. For example, consider the following body-mapping template for a method response of 500 status code:

{ errorMessage: $input.path('$.errorMessage'); }

This template translates the integration response body that contains the custom error JSON string to the following method response body. This method response body contains the custom error JSON object:

{ "errorMessage" : { errorType : "InternalServerError", httpStatus : 500, requestId : context.awsRequestId, trace : { "function": "abc()", "line": 123, "file": "abc.js" } } };

Depending on your API requirements, you may need to pass some or all of the custom error properties as method response header parameters. You can achieve this by applying the custom error mappings from the integration response body to the method response headers.

For example, the following OpenAPI extension defines a mapping from the errorMessage.errorType, errorMessage.httpStatus, errorMessage.trace.function, and errorMessage.trace properties to the error_type, error_status, error_trace_function, and error_trace headers, respectively.

"x-amazon-apigateway-integration": { "responses": { "default": { "statusCode": "200", "responseParameters": { "method.response.header.error_trace_function": "integration.response.body.errorMessage.trace.function", "method.response.header.error_status": "integration.response.body.errorMessage.httpStatus", "method.response.header.error_type": "integration.response.body.errorMessage.errorType", "method.response.header.error_trace": "integration.response.body.errorMessage.trace" }, ... } } }

At runtime, API Gateway deserializes the integration.response.body parameter when performing header mappings. However, this deserialization applies only to body-to-header mappings for Lambda custom error responses and does not apply to body-to-body mappings using $input.body. With these custom-error-body-to-header mappings, the client receives the following headers as part of the method response, provided that the error_status, error_trace, error_trace_function, and error_type headers are declared in the method request.

"error_status":"500", "error_trace":"{\"function\":\"abc()\",\"line\":123,\"file\":\"abc.js\"}", "error_trace_function":"abc()", "error_type":"InternalServerError"

The errorMessage.trace property of the integration response body is a complex property. It is mapped to the error_trace header as a JSON string.