We have an API endpoint we are building through API Gateway that can have two possible successful responses: 200 OK if all of the requested data is returned, and a 206 Partial Content if the data is paginated and additional requests are required to fetch all the data.
I found at https://aws.amazon.com/blogs/compute/amazon-api-gateway-mapping-improvements/ that Amazon now allows multiple 2XX responses to be defined, but I cannot attribute both responses to a success in the Integration Response configuration. Right now we have 200 set as the default, but it appears as if we have to specify a Lambda Error Regex for the 206 mapping.
Does this basically mean that I have to fail the 206 with an error message and then use the regex to determine if that message is being sent, and then basically just treat it like a success? Or how can I properly return either a 200 or a 206 as a successful response?
The endpoint that AWS will hit on our server will properly return a 200 or a 206, but when AWS responds to the client it is currently only sending a 200.
Does this basically mean that I have to fail the 206 with an error
message and then use the regex to determine if that message is being
sent, and then basically just treat it like a success?
Yes, that is correct. Quirky, wrong, but it works.
The API gateway doesnt provide sending multiple success 2xx response. Below are some options
Make your lambda or backend application fail and return some json response. Create a regex in integration response and map the response to a particular error code. The matching of regex is done on errorMessage field which can be only get once you throw error from lambda.
Utilise reponse overriding. You can create a default mapping which matches all or some responses and then in the mapping template you can override the status code to whatever you want to send back.
Eg:-
Lambda returns
def handler(event, context):
x = {
"message": "partial"
}
return x
API gateway integration response
Lambda error regex: -
Method response status: 200
Default mapping: Yes
Mapping template:
#set($inputRoot = $input.path('$'))
$input.json("$")
#if($inputRoot.toString().contains("partial"))
#set($context.responseOverride.status = 206)
#end
Related
I have an API gateway set up with an OpenAPI specification and a proxy lambda integration. Request validation is enabled, and also an authorizer lambda.
Let's say I have endpoints GET /foo and POST /bar. The integrations to these endpoints work well, and the requests are validated and authenticated.
The problem is this:
In order to send back any validation errors when an invalid request is made, e.g. with a missing request body property, I have the following response mapping:
x-amazon-apigateway-gateway-responses:
BAD_REQUEST_BODY:
statusCode: 400
responseTemplates:
application/json: |
{"message": "Invalid request body: $context.error.validationErrorString"}
This also works well. However, if I try to call an endpoint that doesn't exist (e.g. GET /baz), I get a very weird default error message from API gateway. From the past I remember getting a HTTP 403 with something like "missing API key" for invalid URLs, which is weird since it should render a 404, but now I get the even stranger body:
{
"message": "'eyJhbGciOiJSUzI <rest of JWT ...>' not a valid key=value pair (missing equal-sign) in Authorization header: 'Bearer eyJhbGciOiJSUzI <...>"
}
In other words, the JWT I send as my bearer token is passed back in an error message, saying it's not a key=value pair.
Thing is, my authorizer lambda is only connected to the valid endpoints (obviously), so it's not being called. But why is the default built-in API gateway route handler parsing my bearer token and deciding it's not a key=value pair (!)? For an endpoint that doesn't exist? I don't have any {proxy+} endpoint at all.
If I try to map all 403 responses (MISSING_AUTHENTICATION_TOKEN, INVALID_SIGNATURE, etc) to custom error messages, as described here, I get no result, despite docs saying the default response for missing URLs is MISSING_AUTHENTICATION_TOKEN. However, if I also override DEFAULT_4XX, it works, I can return a HTTP 404 with a "Not found" message. The problem is that as soon as I override DEFAULT_4XX, it also overrides my BAD_REQUEST_BODY response so that my validation error messages are lost. Apparently DEFAULT_4XX is not matched last, it takes precedence over BAD_REQUEST_BODY!
How can I set up API gateway so that I at the same time can:
Return 404 NOT FOUND for invalid endpoints such as GET /baz
Return 400 with the $context.error.validationErrorString variable for requests that failed validation
I've found this question that described a similar problem, but surely it's not required to create a {proxy+} integration and/or a dedicated separate lambda only to return a 404 error, this must be possible to achieve by configuration!?
I used the openAPI mock proxy (no lambda) solutions documented here: not a valid key=value pair (missing equal-sign) in Authorization header
It is working very well.
I have an AWS Lambda integrated into API Gateway. The lambda is current just returning an error:
exports.handler = (event, context, callback) => {
context.fail(JSON.stringify({
status: 500,
errors: 'This is definitely the same endpoint.'
}));
};
I have added an HTTP status 500 response in method response of API Gateway, and I have mapped an integration response using regex *"status":500.* to the 500 response.
When I test this using the Method Test functionality in AWS, I get the 500 response I expect:
But when send command to the endpoint with Postman, I get a 200 status:
How can this be? The Method Test seems to suggest my Integration Response and Method Response setups are correct, and I have my regex set up correctly, but what am I missing between the API Gateway and the rest of the world that would produce this different result?
Have you tried Deploying the API? Maybe a redeployment might fix the issues.
did you stumble across the Handle Custom Lambda Errors in API Gateway guide already?
The format suggested there is:
{
"isBase64Encoded" : "boolean",
"statusCode": "number",
"headers": { ... },
"body": "JSON string"
}
So you basically need to return this JSON structure. I check this with AWS serverless express library (line 100-105) - which we use - and it's returning this structure.
The major challenge is, that sending the HTTP response to the client is a task for the API Gateway and to do so, you must return a valid JSON response from the lambda in a format that the API gateway unterstands. The execution status of the lambda will be also 200 (because it worked A-Okay) but the API Gateway will transform your response into a 500. This is also why you nedd this double/triple JSON encoding (JSON-as-string in JSON-attributes).
I am using X-Ray tracing in API Gateway and Lambda authorizer. Inside the authorizer, I am calling two HTTP URLs.
When I give invalid URL for one http call, I am throwing callback ("unauthorized") from lambda authorizer. Hence, the response status will be 401. When I look into the response headers, I couldn't find X-Amzn-Trace-Id.
When the URL is valid and status is 200, X-Amzn-Trace-Id is seen in response headers.
Is there anyway to retrieve X-Amzn-Trace-Id irrespective of the status (always)?
Apologies for delay in the response. We have raised this issue with API Gateway team and actively working with them to resolve this issue. I cannot provide any ETA at this point but please stay tuned. At the moment, there is no way to retrieve "X-Amzn-Trace-Id" irrespective of the status from the response. The "X-Amzn-Trace-Id" is populated by API Gateway segment and it seems missing for the above use case other than 200 status code.
Thanks for the patience.
I have an API Gateway POST endpoint that takes in a JSON request body. I have turned on the body request validator and added the request body model. However the error response I'm getting is only some generic message: "message": "Invalid request body" as defined in the Gateway responses. I'm wondering if it is possible to include the specific validation error in the response? In the logs it says specifically
Request body does not match model schema for content type application/json:
[object has missing required properties (["property1","property2",...])]
Is it possible to have something similar to this in the actual response? Thank you.
In Gateway response for error type BAD_REQUEST_BODY error status 400
set Application/json to {"message":$context.error.validationErrorString}
Ref
https://stackoverflow.com/a/48014686
AWS API Gateway will include more details only if the request payload format is valid, but parameters format is invalid:
{
"message": "Missing required request parameters: [p1]"
}
If the request payload is invalid, you will always receive the same message:
{
"message": "Invalid request body"
}
See the bottom of following page:
http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-validation-test.html
The only way you can get more details is through logs.
By the way, why do you want to send more details through your API, is it for development and debugging only? If yes, using logs is the way to go. You may have some log processing and storage solution to make your debugging easier (e.g. Splunk, Data Dog, Sumo Logic, etc.)
Otherwise, in general, returning too much of technical details in your API error messages is something to avoid.
Sorry for this dumb question, but I tried everything.
I have a AWS API Gateway from a Lambda function that I need to return only HTTP Code 200 with no body. If the lambda returns a empty string, the body shows "" (2 quotation marks). If the lambda returns null, the body shows the word null.
What is the catch? How to return a empty body?
For information, I am using a Slack dash command to call the API. So the call returns a HTTP 200 OK, and the result is sent by POST in a response url; so processing can be done after the HTTP result, in order to avoid timeout problems.
If you are using the "lambda proxy integration" in the "integration request" section (see attached screenshot), you can simply return an empty string through the following structure.
module.exports.hello = (event, context, callback) => {
const response = {
statusCode: 200,
body: ''
};
callback(null, response);
};
I experienced exact the same issue. Lambda Proxy Integration didn't work for me. (Lambda didn't received the request from API Gateway. I think the Proxy disabled Integrated Request > Mapping Template, which transforms slack's application/x-www-form-urlencoded into JSON that Lambda can read.)
Instead, I got another resolution: using Integrated Response. Selected 200 and added Mapping Template then fill in the following code:
#set($inputRoot = $input.path('$'))
After saving and deploying the API (Be sure to return null in the Lambda Function), I got the problem solved. (In my case, I wanted to hide the slash command the user typed in and only show the results.)
I've referenced this article: https://medium.com/#farski/learn-aws-api-gateway-with-the-slack-police-ca8d636e9fc0