NodeJS is a popular scalable server-side JavaScript runtime that is a favorite among full-stack development teams – in fact, it was named one of the “most wanted technologies” in the 2020 Stack Overflow Developer Survey. Serverless code is no different – indeed the first versions of AWS Lambda were built for writing JavaScript in a NodeJS runtime.
In this article, we’ll discuss writing AWS Lambda functions in NodeJS. We’ll review both technologies before exploring local development of AWS Lambda NodeJS functions. Finally, we’ll conclude with some caveats and tips to help improve your development efficiency.
In this article
Since its initial release in 2014, NodeJS has grown into one of the most popular server-side JavaScript runtimes in use today. More than just an API, NodeJS contains a full suite of command-line tools, application libraries, packaging systems, and more to help ease the development of your application’s server code. As NodeJS is written in plain JavaScript code, your developers can work in the same development language throughout the entire stack when coupled with a powerful front-end framework like React.
Launched at Re:Invent in 2014, AWS Lambda took the nascent Function-as-a-Service world by storm. Keying off the popularity of NodeJS, AWS wisely launched AWS Lambda functions with a runtime powered by NodeJS, allowing developers to easily make the transition from server-side coding in NodeJS to serverless development in AWS Lambda. AWS Lambda functions are executed in an on-demand fashion in response to events on the AWS platform. Sources for these events are many, ranging from triggers based on uploads to S3 to data-driven transformation pipelines built on DynamoDB, and finally to http API communications via AWS API Gateway.
Learn more about AWS Lambda in our guide: Complete Guide to AWS Lambda Cost
AWS Lambda functions in NodeJS are essentially the same as any other NodeJS application. There’s an entry function that handles an event, and source code written in JavaScript that processes the event to produce a result. Lambda functions, when invoked, call a handler function that shares the same prototype for every Lambda trigger. The following sample code provides a basic “Hello, world!” Lambda function in NodeJS:
exports.lambdaHandler = async (event, context) => { response = { 'statusCode': 200, 'body': JSON.stringify({ message: 'hello world', }) } return response; };
The exported function, lambdaHandler, is invoked every time this lambda function is triggered. The two parameters, event, and context are provided by the AWS Lambda infrastructure itself and contain valuable information related to the invocation of the function (including the execution context). The event parameter contains details on the invocation event and is where any custom arguments you wish to send to your function will appear. The context parameter contains information on your Lambda functions’ execution context, including information about resource usage quotas that you can use to adjust your functions’ operation, allowing you to more easily control cost overruns.
Learn more about writing AWS Lambda Functions in our guide: Serverless Web Apps with AWS and Kotlin
Given that the power of serverless technology is in the uniformity of its containers, there are some understandable restrictions on the runtime and environment itself. The first is minor and related to how Lambda deploys code itself – namely, you’ll encounter extensive duplication of the deployed code itself. This is not in itself a problem, rather than an annoyance that can arise as your application’s complexity grows. Additionally, Lambdas only support specific NodeJS runtimes (see list).
In terms of the function execution environment, there are a couple of things to be aware of. The first is that you are only given limited access to the operating system layer, meaning that you cannot rely upon operating-system-level packages that might otherwise be available in a more traditional operating environment. The second thing to beware of is that Lambda containers are extremely short-lived, and are regularly recycled for use elsewhere in the system. This means you cannot debug your application based on operating system aspects, such as local file storage, without ensuring that the function context doesn’t exist. This makes post-fact identification of issues much more challenging without dedicated effort up-front.
AWS Lambda functions provide a powerful tool in developing data flow pipelines and application request handlers without the need for dedicated server resources, but these functions are not without their downside. The following tips and tricks may help you navigate the minefield and find serverless success:
● Make extensive use of unit testing. Given the distributed nature of serverless functions, having verification in place is important for peace of mind when deploying your functions that run infrequently. While unit and functional testing cannot fully protect against all issues, it gives you the confidence you need to deploy your changes.
● Beware of time limits. AWS Lambda functions contain inherent time limits in execution. These can go as high as 900 seconds but defaults to 3. If your function is likely to require long run times, ensure you configure this value properly.
● Watch the package size! As code deployments in AWS Lambda are done via variations on zip file uploads, the size of the code matters. AWS Lambda functions, by default, may only upload code that is less than 50 MB in size. Meeting this requirement could require careful monitoring of your node_modules folder.
● Leverage the pattern. It’s easy enough to take a simple NodeJS app and translate it into a monoservice Lambda function, but there are a lot of potential efficiency gains to be made from moving a step or two beyond the basics. Take the time to rebuild your application to take advantage of the event-driven nature of Lambda processing, and you can improve user experience with minimal effort.
● Make use of third parties! It’s powerful to have everything under your control, but it can also be distracting and time-consuming. Tools like Lumigo can provide you automated tracing and online debugging, removing the need to develop these tools from your backlog.
AWS Lambda is a powerful tool for event-driven and intermittent workloads. The dynamic nature of Lambda functions means that you can create and iterate on your functionality right away, instead of having to spend cycles getting basic infrastructure running correctly and scaling properly.
NodeJS, as one of the oldest and longest-supported runtimes in AWS Lambda, allows developers to move into serverless development in a familiar framework. With a careful application of development best practices, you can build a serverless application that is robust, secure, and scalable. Lumigo can help expand your serverless metrics reporting and give you the power you need to drive user value as quickly as possible, driving the observability you need to build your NodeJS Lambda functions and serverless applications.
Learn how easy AWS Lambda monitoring can be with Lumigo