AWS Lambda http headers are coming in the response body - amazon-web-services

I am developing a Rest API with AWS API Gatway(Non proxy) and Lambda. I want to add some headers and change response status code inside lambda.
After lot of googling everyone seems to suggest the following way to achieve this inside lambda.
module.exports.handler = function(event, context, callback) {
const response = {
statusCode: 201,
headers: {
"Access-Control-Allow-Origin" : "*",
"Access-Control-Allow-Credentials" : true
},
body: JSON.stringify({ "message": "Hello World!" })
};
callback(null, response);
};
But the headers and status body is coming in the response body and headers and status code seems to not change. How to fix this?

Related

Access to fetch blocked by CORS policy: Response to preflight request doesn't pass access control check

I am getting this error when trying to fetch REST API from Amazon Web Services in script defined html file:
Access to fetch at '$(url)' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
script
let body = { token: params.token};
const response = await fetch(
url,
{
method: "POST",
body: JSON.stringify(body),
headers: { "Content-type": "application/json", "Access-Control-Allow-Origin":"*" },
}
);
console.log(response);
const myJson = await response.json();
console.log("response-->", myJson);
if (myJson.statusCode != 200) {
console.log("failed");
return;
}
console.log("success");
return;
}
Running into CORS error
API is deployed with below CORS configurations:
enter image description here
Once you'r done with Cors Console Enable (i see that you already done it on the image).
You need to follow this stepts to setup lambda.
And on your function include headers and response in this way:
const headers = {'Content-Type':'application/json',
'Access-Control-Allow-Origin':'*',
'Access-Control-Allow-Methods':'POST'}
const response = {
statusCode: 200,
headers:headers,
body: JSON.stringify({ token: params.token})
};
return response;
so in your fetch you could call it directly and not await it like this:
fetch(...).then((response) => {
return response.json();
})

Getting GET or POST parameters via lambda functional

Recently amazon has released Function Url in Lambda.
I just want to know if we can access Query parameters using it , without using the gateway API.
For example https://functionalurl.aws?id=123
I need to get 123
exports.handler = async (event, context, callback) => {
console.log(event);
callback(null, {
statusCode: 200,
body: context,
headers: {
"Access-Control-Allow-Origin": "*",
},
});
};
Event is always null when I access the function url.

Use multiple same header field in Lambda Proxy Integration

I'm writing a Lambda function that returns a response for Lambda Proxy Integration in Python. The API expects headers to be a dictionary.
{
"isBase64Encoded": true|false,
"statusCode": httpStatusCode,
"headers": { "headerName": "headerValue", ... },
"body": "..."
}
This requires each header field to be unique, so there is no way to use multiple Set-Cookie's.
I've already tried to convert the dictionary to a list of tuples
{
"isBase64Encoded": true|false,
"statusCode": httpStatusCode,
"headers": [ ("headerName": "headerValue"), ... ],
"body": "..."
}
but API gateway complains Malformed Lambda proxy response.
Any idea how to set headers with the same name?
It is currently not possible to send multiple cookies with lambda integration.
If you send multiple set-cookie, then it will take the last one. ok, such a junk implementation right.
Reference, How can I send multiple Set-Cookie headers from API Gateway using a proxied Lambda
Let us see other avaialable options,
Lambda#Edge:
Here is what I find working with Lambda#Edge,
You can create a lambda function for viewer response and modify the header to set cookies.
'use strict';
exports.handler = (event, context, callback) => {
const response = event.Records[0].cf.response;
const headers = response.headers;
// send via a single header and split it into multiple set cookie here.
headers['set-Cookie'] = 'cookie1';
headers['Set-Cookie'] = 'cookie2';
callback(null, response);
};
API Gateway Integration Request mapping:
Here is what I found and got working with integration request,
Hope it helps.
Lambda#Edge:
It is possible to set the headers this way:
response.headers['set-cookie'] = [
{ key: 'Set-Cookie', value: 'cookie1=value1' },
{ key: 'Set-Cookie', value: 'cookie2=value2' },
]
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html#lambda-event-structure-response
API Gateway:
Use multiValueHeaders:
response.multiValueHeaders = {
"Set-Cookie": [
'cookie1=value1',
'cookie1=value1'
]
}
https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-output-format

aws apigateway lambda always return 502

I have created aws apigateway lambda integration for my proxy server. When i am making get request to the gateway, the request is successfully going through. The lambda function also executes successfully and writes response in outputstream with statusCode as 200. But apigateway always returns 502.
Snippet of handleRequest():
BufferedReader reader = new BufferedReader(new
InputStreamReader(inputStream));
JSONObject event = (JSONObject) parser.parse(reader);
request = Input.builder().setEvent(event).build();
Response response = requestManager.handleRequest(request);
logger.log(String.format("Response [%s]", response.toString()));
JSONObject responseJson = new JSONObject();
responseJson.put("statusCode", response.getStatusCode());
responseJson.put("headers", response.getHeaders());
JSONObject jsonBody = (JSONObject) parser.parse(response.getBody());
responseJson.put("body", jsonBody);
OutputStreamWriter writer = new OutputStreamWriter(outputStream, "UTF-8");
logger.log("response recieved");
logger.log(String.format("responseJson [%s]", responseJson));
writer.write(responseJson.toJSONString());
writer.close();
logger.log(String.format("output stream [%s]", outputStream));
Am i missing anything ?
502 errors with Lambda usuaully indicate that you are using the Lambda proxy method and not generating the proper JSON response. Make sure your response adheres to the appropriate format.
If you are still having problems, please share a sample JSON generated by your Lambda function.
I had the same issue where all of my logs were saying the lambda executed successfully but API Gateway was still returning 502s on every request. Turns out I forgot to configure the response status codes in the API Gateway Console so it was throwing errors because the response was "incorrect" even with proper formatting. Just add in a status code 200, 400, 403, etc. to the route on your gateway and that might solve your problem.
Make sure you're hitting your callback with the response before calling context.succeed(event) or some other call to context.
This was my problem and putting my callback first fixed the persistent 502 res.
There are two versions of the response format. It might be that are posting a version 1 format response to an endpoint expecting version 2:
Lambda function response for format 1.0
With the 1.0 format version, Lambda integrations must return a response in the following format.
{
"isBase64Encoded": true|false,
"statusCode": httpStatusCode,
"headers": { "headername": "headervalue", ... },
"multiValueHeaders": { "headername": ["headervalue", "headervalue2", ...], ... },
"body": "..."
}
Lambda function response for format 2.0
With the 2.0 format version, API Gateway can infer the response format for you. API Gateway makes the following assumptions if your Lambda function returns valid JSON and doesn't return a statusCode:
isBase64Encoded is false.
statusCode is 200.
content-type is application/json.
body is the function's response.
The following examples show the output of a Lambda function and API Gateway's interpretation.
Lambda function output
API Gateway interpretation
"Hello from Lambda!"
{ "isBase64Encoded": false, "statusCode": 200, "body": "Hello from Lambda!", "headers": { "content-type": "application/json" }}
{ "message": "Hello from Lambda!" }
{ "isBase64Encoded": false, "statusCode": 200, "body": "{ \"message\": \"Hello from Lambda!\" }", "headers": { "content-type": "application/json" }}
To customize the response, your Lambda function should return a response with the following format:
{
"cookies" : ["cookie1", "cookie2"],
"isBase64Encoded": true|false,
"statusCode": httpStatusCode,
"headers": { "headername": "headervalue", ... },
"body": "Hello from Lambda!"
}

Error Handling in AWS API Gateway and Lambda always return 502

I use serverless to implement Lambda and Api gateway.
When I implement Error Handling, below code always get 502 bad gateway.
handler.js
module.exports.hello = (event, context, callback) => {
const response = {
statusCode: 400,
headers: {
"Content-Type" : "application/json"
},
body: JSON.stringify({
"status": "error",
"message": "Missing Params"
})
};
callback(response);
};
CloudWatch do log error.
{
"errorMessage": "[object Object]"
}
I code this way by following the method "Custom error object serialization" in below AWS blog.
Ref
I change callback first parms to null and work fine. Ref
module.exports.hello = (event, context, callback) => {
const response = {
statusCode: 400,
headers: {
"Content-Type" : "application/json"
},
body: JSON.stringify({
"status": "error",
"message": "Missing Params"
})
};
callback(null, response);
};
This is a common pattern in Node.js and its called Error-First Callbacks.
Basically, if you pass a first argument into your callback, it will be considered and handled as an Error.
As you mentioned, once you put a callback(null, response);, it all worked as expected, since the first argument is null.