I am reading this AWS blog post to learn how to make my static website's form POST data to API Gateway and Lambda.
Most of it makes sense to me, but the Lambda code provided contains this unused variable:
var response = {
"isBase64Encoded": false,
"headers": { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': 'example.com'},
"statusCode": 200,
"body": "{\"result\": \"Success.\"}"
};
I believe this is needed (based on this AWS documentation), but is it used automatically? Or is the Lambda missing some vital code? For example:
callback(null, response)
Side note: In the blog post, the integration set up is not the lambda proxy one, but rather lambda custom integration - https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-custom-integrations.html
To the question: I am pretty sure that the post contains a typo in context.done(err, null); which should have been context.done(err, response);
However as a result this is not an error, as the custom lambda integration response template is just passing through the empty data and the method response is set to 200 with an empty body.
The response object you are referring to needs to be returned back to the client with the structure provides. The code that you are referencing in the AWS article isn't sending any responses back to the client and that is why you are not seeing the response variable implemented anywhere. To complete the handler function you would return that response variable and transforming the body property to what message you intend to send back to your client. Without this return structure, you will get a 502 error on the client.
Related
I have created a sample HTTP API (which is currently in a beta release) using the API gateway. This API does not use any authentication and has a lambda as an integration. The route accepts any HTTP method and I have confirmed that the lambda has the proper API gateway permission. This permission was added when I created the API.
However, when I call the API I receive an HTTP status of 500 and a body of: {"message":"Internal Server Error"}.
This same lambda and API will work if I set it up as a REST API rather than an HTTP API.
Any ideas why this isn't working in the HTTP API?
I had a similar issue with Internal Server Error. I was using the new API Gateway HTTP API (beta) with a nodejs lambda integration. The lambda on its own worked and the REST API worked fine, like you noted.
The 2 issues that cost me 8 hours:
I had to add an async prefix to the handler or use a callback, but I couldn't just return a response without async. See https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html
The response structure has to be correct, see this page: https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html#api-gateway-proxy-integration-create-lambda-backend, scroll to the example function code and you'll see this:
// The output from a Lambda proxy integration must be
// in the following JSON object. The 'headers' property
// is for custom response headers in addition to standard
// ones. The 'body' property must be a JSON string. For
// base64-encoded payload, you must also set the 'isBase64Encoded'
// property to 'true'.
So my function ended up looking like this, note the async and the proper response structure:
exports.handler = async function(event, context) {
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!')
};
return response;
}
This is similar to this post API-Gateway Integration Request HTTP Header not mapping query string to header but I can't see any answer for it and all of the answers are not related to what the question is intended.
I am trying to add the integration request parameters in API Gateway, but whenever I set 'Http Headers' as shown here and 'Mapping template' as passthrough, I could not see that header when I log inside the lambda.
Also in the integration response I cannot reference it inside the integration header response parameters. The "integration.response.header.cokers" will be returned blank when I invoke the API. This is how I configured the integration response
Ultimately the solution here is to implement a lambda proxy integration.
A proxy integration in API Gateway tells API Gateway to simply forward all headers to the integration for processing, which means you will see all of those values in your lambda function.
NOTE: Lambda has to return a specific response format back to API Gateway if it's a proxy integration. Ultimately, the response should be something like:
{
'statusCode': 200,
'headers': {
'echo-proxy': True
},
'body': 'some payload'
}
What you are trying to do right now is map everything manually, which is a deprecated approach and usually you don't want to do that unless you absolutely have to because it's kind of a pain.
If you have to map the headers manually start by mapping them in the the method request so it can carry on to the next step and so on. Basically like this:
Method Request -> Maps variable to Integration Request -> Maps variable to Body Mapping Template -> Maps variable to actual request header
What you have in your screenshot for the Integration Request -> HTTP Headers is:
Name: cokers
Mapped from: 'blah'
However, "mapped from" should look something like "method.request.header.coker" which is a standardized path (meaning to get the value from the Method Request Header field with name "coker").
Once you have added the coker header to the Method Request, and the Integration Request HTTP Headers are mapped correctly, you have to implement a mapping template. Set the content-type to application/json with passthrough set to "When there are no templates defined(recommended)" and a simple mapping template:
{
"headers": {
"coker" : "$input.params('coker')"
}
}
That is the way my API is setup and it returns the following to me because I had my lambda function return the event as a json object back to API GW:
{"body": "{\"headers\": {\"coker\": \"mapped\"}}", "statusCode": 200}
NOTE: the value of my header "coker" in the request on the client side is "mapped"
UPDATED ANSWER
To map the original "coker" header to "coker2" (or any other name you want to give it) you simply set the name of the header in your mapping template like so:
{
"headers": {
"coker2" : "$input.params('coker')"
}
}
Then edit your lambda function to return "coker2" header and you should get a response like this:
{"body": "{\"headers\": {\"coker2\": \"mapped\"}}", "statusCode": 200}
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).
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
My API Gateway/Lambda setup returns an HTTP response header:
Lambda uses callback function to return the value as part of a JSON
and the Integration Response maps it into a HTTP header (using integration.response.body)
With this solution, the values are sent back both in the body and the header.
How can I map headers from the Lambda response without duplicating the values in the response body?
If you have Lambda proxy integration enabled, you can set the response headers as part of Lambda output and API Gateway will return them as part of the HTTP response to the client.
Node.js example:
callback(null, {
"isBase64Encoded": false, // Set to `true` for binary support.
"statusCode": 200,
"headers": {
"header1Name": "header1Value",
"header2Name": "header2Value",
},
"body": "...",
});
where headers can be null or unspecified if no extra response headers are to be returned.
See Output Format of a Lambda Function for Proxy Integration.
and, if you DON'T have Lamba proxy integration enabled, you can add (and map) the response headers in the amazon API gateway console:
go to resources -> method execution -> method response -> add 'Access-Control-Allow-Origin' (or whatever) header for http status 200. Then go back to method execution -> integration response -> http status 200 -> set header mapping for 'Access-Control-Allow-Origin' to '*' (or whatever).
Solved this error...: "No 'Access-Control-Allow-Origin' header is present on the requested resource"
Since the question states that custom mappings are being used (using integration.response.body), it means Lambda Proxy Integrations are NOT being used. So, the solution, in this case, is to map the headers the way you are already doing.
To remove the headers duplication from the body part, use mapping template in the integration response and ignore headers in the mapping. I think you might be using pass through responses, that's why you are seeing duplicate headers.
See more documentation here: https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html