Call a lambda from another Lambda all locally within Serverless - node.js

I am using serveless + aws + node.js.
I have a lambda calling another lambda. I can't get to run the lot locally.
I can invoke both lambdas locally with 'serverless invoke local -f ...' BUT
the caller one comes back with:
{"message":"Function not found: arn:aws:lambda:eu-west-1:5701xxxxxxxxxx:function:the-right-function-name"}
as if the caller function invoked the callee on AWS and not locally.
Is there anyway to do stay local and if yes, what may I be missing?

You can achieve that with this plugin. There is a feature of AWS SDK for Lambda that allows you to override the API endpoint of Lambda service. Therefore you can set it to localhost.
const AWS = require('aws-sdk');
const endpoint = process.env.SERVERLESS_SIMULATE ?
process.env.SERVERLESS_SIMULATE_LAMBDA_ENDPOINT :
undefined
const lambda = new AWS.Lambda({ endpoint })
For more details, refer to the plugin's readme. Also there is a nice article about that.

Related

Node.js async map function ignores async with AWS Lambda

I just had two of these issues back to back. One was with an AWS Lambda function I wrote and one was with deploying to Vercel, which also uses AWS Lambda I believe.
In both cases, running the code locally was fine, but deploying and running with Lambda produced unexplained issues that I eventually tracked down to this:
array.map(async () => {
await ...
})
with AWS Lambda, the asynchronous map function doesn't behave asynchronously at all. Now that I look at it, I must be doing something wrong, but it seems to works asyncrhonously on my local machine.

How to approach use of environment variables for Lambda#Edge

I'm building Lambda function for CloudFront which checks if request has cookies, if not then forwards to login page. I need to customize response header location based on environment - for each env that will be different.
Initially I tried with environment variables but I got an error during deployment:
InvalidLambdaFunctionAssociation: The function cannot have environment variables
So I switched to use aws-sdk with SSM ssm.getParameter but after zipping lambda archive with aws-sdk and one more depedency it's around 13 MB. The limit for Lambda#Edge functions is 1 MB.
I'm wondering would be the best way to approach that. Generate file with environment variables on each Lambda build and require it in index.js?
Use SSM but don't include AWS SDK in your Lambda function. Lambda documentation says that the AWS SDK is included in the Lambda runtime.
To test this, I created a new Node.js 12 Lambda function from scratch in the Lambda console & replaced its existing code with this:
const AWS = require('aws-sdk');
const SSM = new AWS.SSM();
exports.handler = async() => {
return {
statusCode: 200,
body: await SSM.getParameter({ Name: 'my-param' }).promise(),
};
};
This works! Downloading the deployment package of this function from the Lambda console showed that it's just 276 bytes in size. I then deployed this to Lambda#Edge & that worked too!

Failed attempts to write to DynamoDB Local

I recently discovered DynamoDB Local and started building it into my project for local development. I decided to go the docker image route (as opposed to the downloadable .jar file.
That being said I've gotten image up and running and have created a table and can successfully interact with the docker container via the aws cli. aws dynamodb list-tables --endpoint-url http://localhost:8042 successfully returns the table I created previously.
However, when I run my lambda function and set my aws config like so.
const axios = require('axios')
const cheerio = require('cheerio')
const randstring = require('randomstring')
const aws = require('aws-sdk')
const dynamodb = new aws.DynamoDB.DocumentClient()
exports.lambdaHandler = async (event, context) => {
let isLocal = process.env.AWS_SAM_LOCAL
if (isLocal) {
aws.config.update({
endpoint: new aws.Endpoint("http://localhost:8042")
})
}
(which I have confirmed is getting set) it actually writes to the table (with the same name of the local dynamodb instance) in the live AWS Webservice as opposed to the local container and table.
It's also worth mentioning I'm unable to connect to the local instance of DynamoDB with the AWS NoSQL Workbench tool even though it's configured to point to http://localhost:8042 as well...
Am I missing something? Any help would be greatly appreciated. I can provide any more information if I haven't already done so as well :D
Thanks.
SDK configuration changes, such as region or endpoint, do not retroactively apply to existing clients (regular DynamoDB client or a document client).
So, change the configuration first and then create your client object. Or simply pass the configuration options into the client constructor.

Reuse of AWS.SNS service from Node.js AWS SDK

When using the SNS client found on AWS-SDK:
const sns = new AWS.SNS({});
Should I reuse this object across calls to save a handshake with the server?
This kind of object is usually stateless and benefits from pooling/cache; However the docs aren't really clear about that.
I believe you should initiate the class outside of your lambda.
AWS will reuse the instance when possible.
E.g.
const AWS = require('aws-sdk')
const sns = new AWS.SNS()
module.exports.handler = async input => {
// use sns class here
return input
}
EDIT:
Link to the official documentation that explains how the lambda execution context works: https://docs.aws.amazon.com/lambda/latest/dg/running-lambda-code.html
Any declarations in your Lambda function code (outside the handler
code, see Programming Model) remains initialized, providing additional
optimization when the function is invoked again. For example, if your
Lambda function establishes a database connection, instead of
reestablishing the connection, the original connection is used in
subsequent invocations. We suggest adding logic in your code to check
if a connection exists before creating one.

AWS Cognito SDK Node.JS Implementation

I am working on a server for an API that I am developing that is being built using node.js and requires the use of AWS Cognito. Before this, we developed a working version of this application on client side that used the AWS SDK, and I am currently trying to translate that functionality over to the server side. I am struggling to find a good way of doing this and have a few specific questions that, if answered, would probably allow me to get the implementation I am looking for. Basically, I want to know what the AWSCognito object is and how to access it like I see in the following line of code.
var poolData = {
UserPoolId : 'us-east-###########',
ClientId : '########################'
};
var userPool = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool(poolData);
Currently my code is set up using the complete AWS SDK, installed using [a] and accessed in my code using [b].
[a] npm install --save aws-sdk
[b] var AWS = require('aws-sdk');
Is there a way to access this AWSCognito object from my AWS object? If so, how do I do that? If not, how do I get access to it/is it even possible to access it?
Edit: In broad summary, I just want access to the following functions and have no clue how to access them from a node.js server-
userPool.signUp(username, password, attributes, callback)
cognitoUser.confirmPassword(verification, newPassword, {})
cognitoUser.forgotPassword({})
cognitoUser.authenticateUser(authenticationDetails, {})
userPool.getCurrentUser()
cognitoUser.getSession(callback)
cognitoUser.confirmRegistration(verification, bool, callback)
cognitoUser.updateAttributes(attributeList, callback)
cognitoUser.getUserAttributes(callback)
Edit: Update 1
The AWSCognito object is something being set to a global variable in the window by the AWS Cognito SDK. This is a process that only works client-side (yes I know there are hacky solutions to emulate a window on my server, I would prefer not to use these). Is there an equivalent object on server side that I can access and call functions from?
You can use Cognito in a Node.JS environment, but doing so with the AWS SDK for JavaScript is a bit different from doing so with the AWS Cognito SDK. Based on the names of the functions you want to access, you should take a look at the Cognito Identity Provider Service. Operations that start with admin are meant to be called from a server using AWS credentials.

Resources