How to return nothing in AWS API Gateway? - amazon-web-services

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

Related

AWS Documentation: How is Lambda's response var used in API Gateway?

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.

API Gateway new (beta) http api

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;
}

AWS API Gateway integration request Http headers not being passed to lambda

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}

AWS API Gateway returning different status via Postman to Method Test

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).

How do you add JSON data to an HTML AWS lambda response body?

I've run into some trouble with a site I am building. It used AWS lambda functions. I am building and deploying on AWS CodeStar.
The site strips the URL parameter (e.g. /BTC), sends that to external API endpoint, which returns some JSON data. I can display the entire JSON response using body: JSON.stringify(response), so it is definitely coming through from the API. However, I would like to the JSON values to HTML markup before sending back to the client. Yet, when I do something like var html = '<h1>JSON.stringify(response['DISPLAY']['BTC']['USD']['MARKET'])</h1>';. I receive an Internal Server Error - Malformed Request.
I can't figure this out. I'm fairly new to the world of AWS, so may be overlooking something, I've looked around in the docs and can't seem to find anything related to this.
Also, when I had the JSON.stringify output displaying on the webpage. If I re-parsed this in the browser console, response['DISPLAY']['BTC']['USD']['MARKET'] returned a value - so I am fairly sure the syntax for the payload data is correct.
exports.get = function(event, context) {
var ticker = event.pathParameters.currency;
rp(`https://min-api.cryptocompare.com/data/pricemultifull?fsyms=${ticker}&tsyms=USD`)
.then(function (response) {
var html = `<h1>${JSON.stringify(response['DISPLAY']['BTC']['USD']['MARKET'])}</h1>`;
context.succeed({
statusCode: 200,
body: html,
headers: {'Content-Type': 'text/html'}
});
})
.catch(function (err) {
console.log('error: ', err);
});
};
Any help would be appreciated! Happy to provide more info if required.
This is caused by a combination of a couple of things, as far as I can tell:
Within your .catch block you are not calling context.error. In other words, if there's an error in your lambda function, the lambda function never signals that it's finished executing properly to the invoker. API gateway throws up its hands in despair and spits out a 502 error.
response is a string, so when you try to access its properties, you cause an exception and end up in your .catch block. First you need to JSON.parse(response)
Here's a helpful note: whenever you call console.log, the log output can be found in CloudWatch > Logs > /aws/lambda/<your-lambda-name>. This can be useful for figuring out why/where things are breaking.