HTML from lambda invoked by Kong has double quotes - aws-lambda

I’m trying to return an HTML from a lambda that gets invoked by Kong as a RequestResponse invocation.
This is how the lambda looks like:
exports.handler = function(event, context, callback) {
context.succeed('<h2>bleh</h2>')
};
This ends up with something like this:
Notice the double quotes on the page.
I’ve explicitly set the content type to HTML in response transformer for this lambda invocation.
I tried sending a byte array instead, and also switched to using the callback method instead of context.succeed.
How should I go about fixing this?

Using the "is_proxy_integration" configuration that the kong AWS lambda plugin provides helped solved the problem. Check documentation.
This behaves similar to the AWS API gateway integration. Read about it here.
I had to tweak my lambda to return this instead, which made it work:
exports.handler = function(event, context) {
context.succeed({
statusCode: 200,
headers: {'content-type': 'text/html'},
body: "<h1>bleh</h1>"
});
};

Related

Calling POST method in serverless offline using Postman

I'm running serverless offline in node.js. When I try hitting the POST endpoint on Postman the request goes on forever and does not seem to call my handler. I'm not sending anything in the request body. It did not make a difference.
Below are examples of the code I'm running
handlers.js file
module.exports.postHandler = async (event, context, callback) => {
console.log("Inside POST Method");
}
Inside serverless.yml
postHandler:
handler: src/handlers.postHandler
events:
- http:
method: post
path: v1/post/handler
I have a GET method setup very similarly. That looks to be working fine
Edit:
I tried sending an empty request on an invalid POST route. Postman still keeps sending the request endless. When I try the same with GET I get the error - Serverless-offline: route not found. Not sure why POST requests do not resolve.
You need to respond to the client in your post request handler, you dont. Return 200 and give an empty json response it will work
Also make sure you are posting to the API POST Route, and giving it data it needs. i.e)
example:
// dont forget content type and content length headers
POST(host, path, { body: { ...data } })
example get:
GET(host, path, "?query=params")
Your current handler
module.exports.postHandler = async (event, context, callback) => {
console.log("Inside POST Method");
}
do,
module.exports.postHandler = async (event, context, callback) => {
context.status = 200;
context.message = "Youre welcome"
}

Is it safe to call an async function during lambda nodejs init?

I would like to know whether it is safe to make HTTP(S) requests during the Init phase of a NodeJS Lambda function. In particular, I would like to make calls to AWS SSM GetParameter using #aws-sdk/client-ssm or AWS KMS Decrypt using #aws-sdk/client-kms to load secrets that will be used within the handler.
I have found one example online of someone creating a Promise outside of the handler and then awaiting it within the handler (Async Initialisation of a Lambda Handler), but I haven’t seen this approach endorsed in the official Lambda sample applications. None of the official examples do any work outside of the handler.
According to AWS Lambda execution environment: Lambda execution environment lifecycle, “Lambda freezes the execution environment when the runtime and each extension have completed and there are no pending events.” AWS Lambda Runtime API: Next invocation elaborates on the http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next endpoint, “Do not set a timeout on the GET call. Between when Lambda bootstraps the runtime and when the runtime has an event to return, the runtime process may be frozen for several seconds.” I take this to mean that Lambda will signal the process with SIGSTOP at the time of the next call if Provisioned Concurrency is enabled as well as between requests.
In addition, when I look at lambcli’s lambda sources (docker run -it --rm lambci/lambda:build-nodejs12.x cat /var/runtime/Runtime.js), I see that scheduleIteration calls setImmediate(() => this.handleOnce()…) which calls this.client.nextInvocation so I don’t see a way to delay the nextInvocation call.
Questions:
In the Lambda nodejs runtime, is it possible to perform a HTTP request and await its response entirely within the Function init phase?
If you make a request outside of the handler, will the server time out the connection, resulting in Connection Closed errors when the handler awaits the response?
Is there a better recommended way to perform one-time initialization of secrets?
While I'm not able to fully answer all of your questions, I found this blog post that describes a possible solution: https://barker.tech/aws-lambda-nodejs-async-init-88b5c24af567
So in the end, the answers would be:
Yes, it is possible - see linked blog post.
Yes, it will time out. At least, this is what I experienced an issue when I tried to establish a MongoDB-connection outside the function handler with Provisioned Concurrency configured.
I can't really help you with that one...
AWS recently added top level await support in node14 and newer lambdas: https://aws.amazon.com/blogs/compute/using-node-js-es-modules-and-top-level-await-in-aws-lambda/ . Using this you can simply make the init phase wait by using top level await like so:
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
console.log("start init");
await sleep(1000);
console.log("end init");
export const handler = async (event) => {
return {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
};
This works great if you are using ES modules. If for some reason you are stuck using commonjs (e.g. because your tooling like jest or ts-node doesn't yet fully support ES modules) then you can make your commonjs module look like an es module by making it export a Promise that waits on your initialization rather than exporting an object. Like so:
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
const main = async () => {
console.log("start init");
await sleep(1000);
console.log("end init");
const handler = async (event) => {
return {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
};
return { handler };
};
# note we aren't exporting main here, but rather the result
# of calling main() which is a promise resolving to {handler}:
module.exports = main();

Calling lambda recursively in sam local invoke

How can I recursively call lambda inside itself in sam local environment?
const AWS = require('aws-sdk');
const lambda = new AWS.Lambda();
exports.foo = async(event, context) => {
// .......
lambda.invoke({ FuncitonName: context.functionName, InvocationType: 'Event', Payload: {/* .... */}})
}
This apparently does not work.
EDIT
My usecase is to split data to prevent timeout.
Payload contains page number and this lambda fetches data from API with the page number and put it to DynamoDB.
Returning result to caller is not important so async invocation is fine.
If you need to call other function I would recommend using localstack which has better support working with lambda functions locally and inter-calls between them.
sam local is fine if you work only with the function itself but once you have integration with s3, dynamodb, sqs, lambda better to use localstack

Error from cloudfront in serverless framework lambda function

I am trying to deploy a simple Slack lambda api which uses the #slack/client library to remove members and pinned messages from a specific channel. The issue that I am running into is the function executes without a problem, and it is removing the channel members without a problem, but my Lambda function keeps returning:
HTTP/1.1 502 Bad Gateway
...
X-Cache: Error from cloudfront
...
{
"message": "Internal server error"
}
as the response body. When I check the logs using sls logs -f api, I dont see any errors there either. I see the console.log of my function successfully executing.
My serverless.yml is as follows:
provider:
name: aws
runtime: nodejs10.x
profile: serverless
functions:
api:
handler: handler.api
timeout: 30
events:
- http:
method: POST
path: clean
And my api code, i have removed the unnecessary function codes as they are doing their work, is :
module.exports.api = async (event, context, callback) => {
let channel = JSON.parse(event.body).ctf
let id = await findChannelId(channel)
removeMembersFromChannel(id[0]).then(() => {
removePinsFromChannel(id[0]).then(() => {
callback(null, {
statusCode: 200,
body: JSON.stringify({
message: `Cleaned ${channel} ${id}`,
}, null, 2),
})
})
})
};
Things I have tried:
returning the response instead of using the callback
using promises and async await
testing the function locally using sls invoke local
most of my search shows that this could be a permission issue, but all the references are for s3 usage which is something i am not using.
Questions
Why am I getting this error, and how I can resolve this?
After referenceing this In the handler function, I am using JSON.stringify. Using the serverless-framework, how can i avoid using Lambda proxy integration?
Please, add console.log for detailed logging via cloudwatch and use x-ray. Some typical problems with cloudfront:
- a lot of time to propagate to edge locations (maybe u need recreate your cdn)
- logs from lambda#edge locates in invoked region

AWS Lambda call Lambda

I'm trying to call one Lambda function from another one that I have. I set up my permissions so that is not problem.
My problem is that the function doesn't wait for the Invoke function to complete and return NULL all the time.
Here is the code I'm using:
const AWS = require('aws-sdk');
exports.handler = async (event, context, callback) => {
var lambda = new AWS.Lambda({region: 'us-east-1', apiVersion: '2015-03-31'});
var params = {
FunctionName: 'testFunction',
InvocationType: 'RequestResponse'
}
lambda.invoke(params, function(err, data){
console.log(err);
console.log('here');
}).promise().then(data=> { callback(null, {message:'done'}); });
};
The {message:'done'} its never shown. I was recommended to use invokeAsync but that function is deprecated by AWS.
I know the problem is that the function is running lambda.invoke as synchronously because if I add callback(null, {message:'done'}); outside of the lambda.invoke function then I can see the console.logs working.
Any help?
TL;DR - Remove "async" in line 3, and it should work.
Your issue seems to be caused by the async keyword here. I have recreated this and deployed it to Lambda to run on Node v8.10 (but pointing it to invoke one of my own lambda functions of course).
Why are you using "async" here anyway? The async keyword declaration defines an asynchronous function and returns an AsyncFunction object. AWS Lambda is expected a function, not an AsyncFunction, and your "null" result is probably just Lambda immediately giving up because it can't find a regular function. Also, async is almost exclusively used with await (at least is was in 99% of the cases I've seen), and since your code isn't using await at all I don't see any reason to use async either.

Resources