The post was updated on 9 August 2023 to use the current LTS version of Node (v18), AWS CLI (2.13.3) and SAM CLI (1.94.0).
AWS Lambda has been around for a few years now, and it remains the most popular way to experiment with serverless technology. If you're not familiar with serverless, it's a model of development in which managing, provisioning, and scaling servers is abstracted away from application development. Servers do exist in a serverless world, but they are completely managed by the cloud provider, allowing developers to focus on packaging their code for deployment.
AWS Lambda is a type of Function-as-a-Service (FaaS) offering that allows code execution on demand in response to preconfigured events or requests. This post will introduce you to AWS Lambda and guide you on creating and deploying Lambda functions with Node.js and AWS SAM.
Let's get started!
Prerequisites
Before you proceed with this tutorial, ensure that you have Node.js 18.x LTS installed on your computer, as this is the latest release that AWS Lambda supports at the time of writing. However, the content of this article should stay relevant even when newer releases are supported. You can use Volta to install and manage multiple versions of Node.js on your computer. Also, ensure you sign up for a free AWS account if you don't have one already.
If you intend to run your AWS Lambda function locally (which I'll be demonstrating in this article), you'll need Docker installed on your computer. Follow these instructions to set up Docker for your operating system before proceeding with the rest of this tutorial.
Install the AWS CLI and AWS SAM CLI
In this guide, we'll be using both the AWS CLI and the AWS Serverless Application Model (SAM) CLI to develop our serverless functions and deploy them to AWS.
The former interacts with AWS services on the command line, while the latter helps with building, debugging, deploying, and invoking Lambda functions. Read more about AWS SAM in the docs.
The exact way to install both CLI tools will differ depending on your operating system. You can install or upgrade to the latest version of AWS CLI for Linux, macOS, and Windows by following the instructions on this page. To install the AWS SAM CLI, check this page for the relevant guide for your operating system.
Here are the versions of AWS CLI and AWS SAM CLI that I installed while writing this guide:
After you've installed both CLI tools, follow this guide to set up your AWS credentials so that you can interact successfully with your AWS account via the CLIs.
Create Your First AWS Lambda Function with Node.js
Let's start by writing a simple hello world function to demonstrate how AWS Lambda works. Run the command below to initialize a new project:
When prompted, choose AWS Quick Start Templates under template source, Hello World Example under application templates and also under starter templates, select N for X-Ray tracing and N for monitoring with CloudWatch.
Once the command exits, change into the freshly minted
aws-lambda-nodejs-example
folder. It should have the following folder
structure:
Here's a short description of the important files and directories in the project:
template.yaml
: Defines the AWS resources for your application.hello-world/app.mjs
: Contains the Lambda function logic.hello-world/package.json
: Contains any Node.js dependencies required by the application.hello-world/tests/
: Contains unit tests for your Lambda functions.
Open up the template.yaml
file in your text editor and take note of the
following lines:
These lines describe the name of your Lambda function (HelloWorldFunction
),
the runtime used to execute it (nodejs18.x
), and the type of trigger for the
function (Api
). This indicates that your Lambda function will execute when a
GET request is sent to the /hello
route via API
Gateway. Note that there are several
other ways
to invoke Lambda functions.
The CodeUri
line indicates that the code for the HelloWorldFunction
is in
the hello-world
directory. The Handler
property specifies app.mjs
as the file with
the function code, which should have a named export called
lambdaHandler
.
Open up the hello-world/app.mjs
file and examine its content:
This simple function takes two parameters and returns a response object
containing a 'hello world' message. The first parameter is the JSON payload sent
by the invoker of the function, while the second is the context object which
contains information about the function invocation and execution environment.
This handler is async
, so you can use return
or throw
to return a response
or an error, respectively. Non-async
handlers
must use a third callback
parameter (not shown here).
Go ahead and modify the function to return the reserved environmental variables defined in the runtime environment instead of the hello world message.
We can access the environmental variables through process.env
and,
after aggregating them in an object, return them in the response object. API Gateway uses the
statusCode
property to add the right HTTP status code
to the generated response.
Testing Your AWS Lambda Function Locally
Before deploying your function, you'll want to test it locally to confirm it works as expected. To do so, run the following SAM command at the root of your project directory:
This command requires Docker, so make sure it's installed and running on your computer. Otherwise, you might get an error message similar to the one shown below:
If you are still getting the above error despite Docker running, check your user permissions — you can, for instance, configure the docker
command to run without sudo
.
Once the application is running, make a GET request to
http://localhost:3000/hello
. This will cause AWS SAM to start a Docker
container to run the function. Once the container is up and running, the
function will execute and the following result will be returned:
You can use jq to prettify the output if you have it installed:
You can also test your Lambda function without making an HTTP request to trigger it. The SAM CLI provides a way to invoke the function using a predefined JSON file. Run the following command in your project root to try it out:
The event that triggers a Lambda function usually comes with a JSON payload. You should provide this payload using the --event
option (as demonstrated above) to invoke the function locally. This payload passes as the first
argument to the Lambda function. The event.json
file is created by the SAM
CLI when initializing the project, so it may be used for this purpose.
Learn more about events.
When you invoke a function locally, you'll get some information on:
- the Docker container image used to execute the function
- how long it ran for
- how much memory was used
You'll also get the actual return value of your function below the runtime information.
Deploying the Lambda Function to the AWS Cloud
Once you are happy with how your function runs locally, you can deploy it to the
AWS Cloud through the SAM CLI. First, run sam build
to generate artifacts
that target AWS Lambda's execution environment:
Next, run sam deploy --guided
to deploy the function, and answer the prompts as
shown below:
Once deployment is successful, you will see the API Gateway URL in the output. It should have the following structure:
Once you make a GET request to that URL, your function will execute, and you'll get a similar output as before:
Congratulations, you've successfully deployed your first Lambda function to production!
Using NPM Packages in AWS Lambda Functions
Let's go ahead and create a new Lambda function that uses some NPM packages to
perform a web scraping task. Create a new folder called quotes-scraper
in your
project directory and initialize it with a package.json
file:
Afterward, create an app.js
file in the root of the quotes-scraper
directory and populate it with the following content:
This code scrapes the quotes on this website and
returns them as a JSON object. It uses
axios to fetch the HTML and
cheerio to extract the relevant parts. Ensure you
install both dependencies in the quotes-scraper
directory:
Afterward, open the template.yml
file in your project root and add the
following code to the Resources
section:
Next, add the following snippet to the Output
section:
Save and close the file, then invoke your new function through the SAM CLI:
Go ahead and deploy your function with the sam deploy
command.
Afterward, you will be able to invoke the function through the API Gateway
endpoint:
Creating Serverless APIs with AWS Lambda and Node.js: Wrap-Up and Next Steps
I hope this article has helped you learn the basics of building serverless APIs with the help of AWS Lambda and Node.js.
There are so many other topics concerning Lambda functions that we've not covered here, including authentication, logging and monitoring, caching, persisting to a database, and more.
To build on the knowledge you've gained through this tutorial, read up on those topics and check out some of the recommended practices for working effectively with AWS Lambda functions.
Thanks for reading, and happy coding!
P.S. If you liked this post, subscribe to our JavaScript Sorcery list for a monthly deep dive into more magical JavaScript tips and tricks.
P.P.S. If you need an APM for your Node.js app, go and check out the AppSignal APM for Node.js.