Is there a way to change the http status codes returned by the Amazon API Gateway?

For example, if I want to return a specific error 400 for invalid parameters, or possibly 201, when the call to the lambda function led to the creation.

I would like to have different http status codes, but it looks like api gateway always returns a 200 status code, even if the lambda function returns an error.

+54
amazon-web-services aws-lambda aws-api-gateway
Jul 09 '15 at 22:38
source share
9 answers

Update on 20-9-2016

Amazon has finally simplified the use of Lambda Proxy integration . This allows your Lambda function to return the correct HTTP codes and headers:

let response = { statusCode: '400', body: JSON.stringify({ error: 'you messed up!' }), headers: { 'Content-Type': 'application/json', } }; context.succeed(response); 

Say the farewell request / response display in the API!

Option 2

Integrate your existing Express application with your Lambda / API gateway using aws-serverless-express .

+34
Oct 08 '16 at 19:00
source

Here's the fastest way to return custom HTTP status codes and custom errorMessage :

In the API Gateway toolbar, do the following:

  • In the method of your resource, click on the method response
  • In the HTTP Status table, click Add Response and add the HTTP status code you would like to use to each status code.
  • In the method of your resource, click on the integration request
  • Add an integration response for each of the HTTP status codes you created earlier. Verify that the incoming transit check is verified. Use the lambda error regular expression to determine which status code to use when you return an error message from your lambda function. For example:

     // Return An Error Message String In Your Lambda Function return context.fail('Bad Request: You submitted invalid input'); // Here is what a Lambda Error Regex should look like. // Be sure to include the period and the asterisk so any text // after your regex is mapped to that specific HTTP Status Code Bad Request: .* 
  • Your API gateway route should return this:

     HTTP Status Code: 400 JSON Error Response: { errorMessage: "Bad Request: You submitted invalid input" } 
  • I see no way to copy these settings and reuse them for different methods, so we have a lot of annoying redundant manual input!

My integration answers are as follows:

aws api gateway lambda error response handling

+58
Jul 12 '15 at 19:47
source

To return a custom error object in the form of JSON, you need to jump over a couple of hoops.

First, you must skip the Lambda and pass the gated JSON object to it:

 exports.handler = function(event, context) { var response = { status: 400, errors: [ { code: "123", source: "/data/attributes/first-name", message: "Value is too short", detail: "First name must contain at least three characters." }, { code: "225", source: "/data/attributes/password", message: "Passwords must contain a letter, number, and punctuation character.", detail: "The password provided is missing a punctuation character." }, { code: "226", source: "/data/attributes/password", message: "Password and password confirmation do not match." } ] } context.fail(JSON.stringify(response)); }; 

Then you customize the display of regular expressions for each of the status codes you want to return. Using the above object, you should set this regex to 400:

.

* "status": 400 * .

Finally, you configure the mapping pattern to retrieve the JSON response from the errorMessage property returned by Lambda. The matching pattern is as follows:

$ input.path ('$. ErrorMessage')

I wrote an article about this, which is covered in more detail and explains the flow of responses from Lambda to the Gateway API: http://kennbrodhagen.net/2016/03/09/how-to-return-a-custom-error-object-and- status-code-from-api-gateway-with-lambda /

+14
Mar 13 '16 at 15:17
source

1) Configure your API gateway resource to use Lambda Proxy Integration by checking the Use Lambda Proxy Integration checkbox on the Integration Request screen in the API Gateway resource definition. (Or define it in your configuration cloudformation / terraform / serverless / etc)

2) Change your lambda code in two ways.

  • Handle the incoming event (1st argument of the function) accordingly. This is not just a bare payload, it represents the entire HTTP request, including the headers, the query string, and the body. An example is below. The key point is that JSON bodies will be strings requiring an explicit call to JSON.parse(event.body) (don't forget to try/catch around this). An example is below.
  • Answer by calling a callback with a null value, and then a response object that provides HTTP data, including statusCode , body and headers .
    • body must be a string, so JSON.stringify(payload) if necessary
    • statusCode may be a number
    • headers is an object of header names for values

Lambda Event Argument Example for Proxy Integration

 { "resource": "/example-path", "path": "/example-path", "httpMethod": "POST", "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "CloudFront-Forwarded-Proto": "https", "CloudFront-Is-Desktop-Viewer": "true", "CloudFront-Is-Mobile-Viewer": "false", "CloudFront-Is-SmartTV-Viewer": "false", "CloudFront-Is-Tablet-Viewer": "false", "CloudFront-Viewer-Country": "US", "Content-Type": "application/json", "Host": "exampleapiid.execute-api.us-west-2.amazonaws.com", "User-Agent": "insomnia/4.0.12", "Via": "1.1 9438b4fa578cbce283b48cf092373802.cloudfront.net (CloudFront)", "X-Amz-Cf-Id": "oCflC0BzaPQpTF9qVddpN_-v0X57Dnu6oXTbzObgV-uU-PKP5egkFQ==", "X-Forwarded-For": "73.217.16.234, 216.137.42.129", "X-Forwarded-Port": "443", "X-Forwarded-Proto": "https" }, "queryStringParameters": { "bar": "BarValue", "foo": "FooValue" }, "pathParameters": null, "stageVariables": null, "requestContext": { "accountId": "666", "resourceId": "xyz", "stage": "dev", "requestId": "5944789f-ce00-11e6-b2a2-dfdbdba4a4ee", "identity": { "cognitoIdentityPoolId": null, "accountId": null, "cognitoIdentityId": null, "caller": null, "apiKey": null, "sourceIp": "73.217.16.234", "accessKey": null, "cognitoAuthenticationType": null, "cognitoAuthenticationProvider": null, "userArn": null, "userAgent": "insomnia/4.0.12", "user": null }, "resourcePath": "/example-path", "httpMethod": "POST", "apiId": "exampleapiid" }, "body": "{\n \"foo\": \"FOO\",\n \"bar\": \"BAR\",\n \"baz\": \"BAZ\"\n}\n", "isBase64Encoded": false } 

Sample callback response form

 callback(null, { statusCode: 409, body: JSON.stringify(bodyObject), headers: { 'Content-Type': 'application/json' } }) 



Notes - I believe that methods on context , such as context.succeed() , are deprecated. They are no longer documented, although they still work. I think encoding the callback API is the right thing in the future.

+5
Dec 29 '16 at 20:04
source

For those who tried everything, asked this question and were unable to do this work (for example, I), check out thedevkit comment on this post (saved my day):

https://forums.aws.amazon.com/thread.jspa?threadID=192918

Reproducing it completely below:

I had problems with this myself, and I believe that the new line of characters are the culprits.

foo. * will match the occurrences of "foo" followed by any characters EXCLUDING a new line. This is usually solved by adding the "/ s" flag, i.e. "foo. * / s", but the regular expression Lambda error does not look like this.

Alternatively, you can use something like: foo (. | \ N) *

+4
Feb 17 '16 at 17:27
source

I wanted the error from Lambda to be the correct error 500, after doing a lot of research, came up with the following, which works:

At LAMBDA

For a good answer, I come back as shown below:

 exports.handler = (event, context, callback) => { // .. var someData1 = { data: { httpStatusCode: 200, details: [ { prodId: "123", prodName: "Product 1" }, { "more": "213", "moreDetails": "Product 2" } ] } }; return callback(null, someData1); } 

For a bad answer returning as below

 exports.handler = (event, context, callback) => { // .. var someError1 = { error: { httpStatusCode: 500, details: [ { code: "ProductNotFound", message: "Product not found in Cart", description: "Product should be present after checkout, but not found in Cart", source: "/data/attributes/product" }, { code: "PasswordConfirmPasswordDoesntMatch", message: "Password and password confirmation do not match.", description: "Password and password confirmation must match for registration to succeed.", source: "/data/attributes/password", } ] } }; return callback(new Error(JSON.stringify(someError1))); } 

In the API

For a GET METHOD, say GET / res1 / service1:

 Through Method Response > Add Response, added 3 responses: - 200 - 300 - 400 

Then

 Through 'Integration Response' > 'Add integration response', create a Regex for 400 errors (client error): Lambda Error Regex .*"httpStatusCode":.*4.* 'Body Mapping Templates' > Add mapping template as: Content-Type application/json Template text box* $input.path('$.errorMessage') Similarly, create a Regex for 500 errors (server error): Lambda Error Regex .*"httpStatusCode":.*5.* 'Body Mapping Templates' > Add mapping template as: Content-Type application/json Template text box* $input.path('$.errorMessage') 

Now post / res 1 / service1, remove the published url that is associated with the above lambda

When the REST (or Postman) advanced client client is used, you will see appropriate http codes, such as a server error (500) or 400, instead of 200 HTTP response codes for all requests that were specified in "httpStatusCode".

In the "Dashboard" API, in the Gateway API, we can see the http status codes, as shown below:

400 and 500 errors

+1
Dec 27 '16 at 11:05
source

The easiest way to do this is to use the LAMBDA_PROXY integration . Using this method, you do not need special conversions that need to be installed in the API Gateway pipeline.

Your return object should look like the snippet below:

 module.exports.lambdaHandler = (event, context, done) => { // ... let response = { statusCode: 200, // or any other HTTP code headers: { // optional "any-http-header" : "my custom header value" }, body: JSON.stringify(payload) // data returned by the API Gateway endpoint }; done(null, response); // always return as a success }; 

It has several drawbacks: you need to be especially careful in handling errors and associating your lambda function with the endpoint of the API gateway; that if you’re not really going to use it anywhere else, it’s not that important.

+1
Jan 31 '17 at 3:00
source

I am using serverless 0.5. Here's how it works, for my case

S-function.json:

 { "name": "temp-err-test", "description": "Deployed", "runtime": "nodejs4.3", "handler": "path/to/handler.handler", "timeout": 6, "memorySize": 1024, "endpoints": [ { "path": "test-error-handling", "method": "GET", "type": "AWS_PROXY", "responses": { "default": { "statusCode": "200" } } } ] } 

handler.js:

 'use strict'; function serveRequest(event, context, cb) { let response = { statusCode: '400', body: JSON.stringify({ event, context }), headers: { 'Content-Type': 'application/json', } }; cb(null, response); } module.exports.handler = serveRequest; 
0
Oct 21 '16 at 12:07 on
source

So recommended by AWS Compute Blog when using the Gateway API. Check to make sure the integration works with Lambda direct call.

 var myErrorObj = { errorType : "InternalServerError", httpStatus : 500, requestId : context.awsRequestId, message : "An unknown error has occurred. Please try again." } callback(JSON.stringify(myErrorObj)); 

For direct Lambda calls, this seems to be the best solution for client-side processing.

0
Nov 15 '16 at 17:16
source



All Articles