In this article, we'll explore the process of deploying and running a serverless application on AWS Lambda built with Node.js framework such as Hapi.js and NoSQL database like Dynamodb.
In this article, we will use the application that we previously built from this article.
We will use AWS Lambda Web Adapter to run our Node.js Application on AWS Lambda.
AWS Lambda Web Adapter allows developers to build web apps (http api) with familiar frameworks (e.g. Express.js, Next.js, Flask, SpringBoot, ASP.NET and Laravel, anything speaks HTTP 1.1/1.0) and run it on AWS Lambda.
Follow me for more
AWS Lambda
AWS Lambda is a serverless computing service provided by Amazon Web Services (AWS). It allows you to run code without having to provision or manage servers. With Lambda, you can focus on writing your application code and let AWS handle the infrastructure management, scaling, and server maintenance.
Amazon DynamoDB
Amazon DynamoDB is a fully managed NoSQL database service provided by Amazon Web Services (AWS). It is designed to provide fast and scalable performance for applications that require flexible and reliable data storage. DynamoDB is particularly well-suited for web and mobile applications, gaming backends, content management systems, and other use cases that need low-latency, highly available, and scalable databases.
AWS Serverless Application Model
AWS SAM (Serverless Application Model) is an open-source framework provided by Amazon Web Services (AWS) for building serverless applications. It extends AWS CloudFormation, which is AWS's infrastructure as code service, to provide a simplified way of defining the resources and configurations needed to deploy serverless applications on AWS.
Node.js
Node.js is an open-source, server-side runtime environment that allows developers to build and run server-side applications using JavaScript. It is built on the V8 JavaScript engine, which is the same engine used in Google Chrome, and it enables the execution of JavaScript code on the server, rather than just in web browsers.
Node.js Framework
Node.js has a rich ecosystem of frameworks and libraries to simplify web application development. Some popular Node.js frameworks and libraries include:
- Express.js
- Koa.js
- Sails.js
- Hapi.js
- Nest.js
In this article, we will deploy and run our application built with Hapi.js and Amazon DynamoDB.
Prerequisites Tools
Table of Contents
Project Folder Structure
Our project folder structure will looks like this
.
|-- app
| |-- src
| `-- Dockerfile
`-- template.yaml
-
src
is a folder that will houses our Node.js application. -
Dockerfile
is a text file used to define a set of instructions for building our Docker container image. -
template.yaml
is an AWS SAM template, providing a streamlined layer on top of CloudFormation, simplifying the definition and deployment of our serverless applications.
Dockerfile
This is how our Dockerfile looks like
FROM public.ecr.aws/docker/library/node:16.13.2-stretch-slim
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.7.1 /lambda-adapter /opt/extensions/lambda-adapter
EXPOSE 8080
WORKDIR "/var/task"
ADD src/package.json /var/task/package.json
ADD src/package-lock.json /var/task/package-lock.json
RUN npm install --omit=dev
ADD src/ /var/task
CMD ["node", "index.js"]
This is a Dockerfile that defines the build instructions for a Docker image. The image is based on the node:16.13.2-stretch-slim
image from Docker Hub, which is a lightweight version of the Node.js runtime environment.
To use Lambda Web Adapter with docker images, add one line to copy Lambda Web Adapter binary to /opt/extensions inside your container.
The Dockerfile starts by copying the lambda-adapter
binary from another Docker image (public.ecr.aws/awsguru/aws-lambda-adapter:0.7.1
) to the /opt/extensions/lambda-adapter
directory in the new image.
The EXPOSE
instruction is used to indicate that the container will listen on port 8080. This does not actually publish the port, but it is a useful hint for anyone who wants to run the container.
The WORKDIR
instruction sets the working directory for subsequent instructions to /var/task
. This is the directory where the Lambda function code will be located.
The ADD
instructions copy the package.json
, package-lock.json
, and source code files from the src
directory to the /var/task
directory in the image. The npm install
command is then run to install the dependencies specified in package.json
. The --omit=dev
flag is used to exclude development dependencies from the installation, which can help reduce the size of the final image.
Finally, the CMD
instruction specifies the command that should be run when a container is started from the image. In this case, it runs the node
command with index.js
as the argument, which is the entry point for the Lambda function.
SAM Template
AWS SAM (Serverless Application Model) template is a JSON or YAML configuration file used to define the AWS resources and configurations required to deploy a serverless application on Amazon Web Services (AWS).
This is how our complete AWS SAM template will look like.
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: Todo Application
Resources:
TodoFunction:
Type: AWS::Serverless::Function
Properties:
PackageType: Image
MemorySize: 1024
Timeout: 30
Environment:
Variables:
RUST_LOG: info
TABLE_NAME: !Ref TodoTable
Events:
Root:
Type: HttpApi
Properties:
Path: /
Method: ANY
Petstore:
Type: HttpApi
Properties:
Path: /{proxy+}
Method: ANY
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref TodoTable
Metadata:
DockerTag: v1
DockerContext: ./app
Dockerfile: Dockerfile
TodoTable:
Type: AWS::Serverless::SimpleTable
Properties:
PrimaryKey:
Name: id
Type: String
Outputs:
TodoApi:
Description: "API Gateway endpoint URL for Prod stage for Todo function"
Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.${AWS::URLSuffix}/"
First, we defined our Lambda Function resource like this in our template.
TodoFunction:
Type: AWS::Serverless::Function
Properties:
PackageType: Image
MemorySize: 1024
Timeout: 30
Environment:
Variables:
RUST_LOG: info
TABLE_NAME: !Ref TodoTable
Events:
Root:
Type: HttpApi
Properties:
Path: /
Method: ANY
Petstore:
Type: HttpApi
Properties:
Path: /{proxy+}
Method: ANY
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref TodoTable
Metadata:
DockerTag: v1
DockerContext: ./app
Dockerfile: Dockerfile
The above template part defines an AWS Lambda function named TodoFunction
that is used to handle HTTP requests for a RESTful API.
The Type
property specifies that this resource is an AWS::Serverless::Function, which is a type of AWS Lambda function that can be defined using the SAM template format.
The Properties
section contains various configuration options for the function. The PackageType
property is set to Image
, which means that the function will be packaged as a Docker image. The MemorySize
property is set to 1024 MB, which is the amount of memory that will be allocated to the function when it runs. The Timeout
property is set to 30 seconds, which is the maximum amount of time that the function can run before it is terminated.
The Environment
section contains environment variables that will be available to the function at runtime. In this case, there are two variables defined: RUST_LOG
and TABLE_NAME
. The RUST_LOG
variable is set to info
, which is a logging level for the Rust programming language. The TABLE_NAME
variable is set to the name of a DynamoDB table that the function will interact with. The !Ref
function is used to reference the TodoTable
resource defined elsewhere in the template.
The Events
section defines the events that will trigger the function. In this case, there are two events defined: Root
and Petstore
. Both events are of type HttpApi
, which means that they will be triggered by HTTP requests. The Path
property specifies the URL path that will trigger the event, and the Method
property specifies the HTTP method that will trigger the event.
The Policies
section defines the IAM policies that are attached to the function. In this case, there is one policy defined: DynamoDBCrudPolicy
. This policy grants the function permissions to perform CRUD (Create, Read, Update, Delete) operations on the DynamoDB table specified in the TableName
property. The !Ref
function is used to reference the TodoTable
resource defined elsewhere in the template.
The Metadata
section contains metadata about the function. In this case, it specifies the Docker tag, Docker context, and Dockerfile that will be used to build the Docker image for the function.
Then we create our Amazon DynamoDB table
TodoTable:
Type: AWS::Serverless::SimpleTable
Properties:
PrimaryKey:
Name: id
Type: String
The above template part defines an AWS DynamoDB table named TodoTable
that will be used to store data for a RESTful API.
The Type
property specifies that this resource is an AWS::Serverless::SimpleTable, which is a type of DynamoDB table that can be defined using the SAM template format.
The Properties
section contains various configuration options for the table. The PrimaryKey
property specifies the primary key for the table, which consists of a single attribute named id
of type String
. This means that the id
attribute will be used as the partition key for the table.
Last, we defined our function's API Gateway endpoint URL output
Outputs:
NodejsApi:
Description: "API Gateway endpoint URL for Prod stage for Todo function"
Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.${AWS::URLSuffix}/"
It defines an output named TodoApi
that provides the URL for the API Gateway endpoint for the TodoFunction
resource.
The Outputs
section of the template is used to define values that can be exported from the stack. These values can be used by other stacks or by external applications to interact with the resources in the stack.
The TodoApi
output has a Description
property that provides a brief description of the output. In this case, it describes the output as the API Gateway endpoint URL for the Prod
stage of the TodoFunction
resource.
The Value
property is a !Sub
function that substitutes variables in a string with their corresponding values. In this case, it substitutes the ${ServerlessHttpApi}
variable with the name of the HTTP API that is created for the TodoFunction
resource, and the ${AWS::Region}
and ${AWS::URLSuffix}
variables with the AWS region and URL suffix, respectively.
AWS SAM Deploy
To start deploying our serverless application we can run this command in our terminal
sam build
sam deploy --guided
sam deploy --guided
is a command provided by the AWS SAM (Serverless Application Model) CLI (Command Line Interface) that launches an interactive, guided deployment process for your serverless application. This command helps you deploy your application with AWS SAM in an easy and user-friendly manner.
When you run sam deploy --guided
, you will be asked for some configurations input, which you can fill in like this.
Configuring SAM deploy
======================
Looking for config file [samconfig.toml] : Found
Reading default arguments : Success
Setting default arguments for 'sam deploy'
=========================================
Stack Name [sam-app]: hapijs-todoapp
AWS Region [ap-southeast-1]: ap-southeast-1
#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [y/N]: y
#SAM needs permission to be able to create roles to connect to the resources in your template
Allow SAM CLI IAM role creation [Y/n]: Y
#Preserves the state of previously provisioned resources when an operation fails
Disable rollback [y/N]: N
ExpressFunction has no authentication. Is this okay? [y/N]: y
ExpressFunction has no authentication. Is this okay? [y/N]: y
Save arguments to configuration file [Y/n]: Y
SAM configuration file [samconfig.toml]: samconfig.toml
SAM configuration environment [default]: default
AWS SAM will start looking for resources needed for deployment we defined in our template.
Looking for resources needed for deployment:
Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-1aa02zp34lw9q
A different default S3 bucket can be set in samconfig.toml and auto resolution of buckets turned off by setting resolve_s3=False
Image repositories: Not found.
#Managed repositories will be deleted when their functions are removed from the template and deployed
Create managed ECR repositories for all functions? [Y/n]:
Saved arguments to config file
Running 'sam deploy' for future deployments will use the parameters saved above.
The above parameters can be changed by modifying samconfig.toml
Learn more about samconfig.toml syntax at
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html
eb03fb97f024: Pushed
421b36cec0ce: Pushed
85de5da90a78: Pushed
29f371b320ea: Pushed
f2ca56bec846: Pushed
7c5fbd8aa99c: Pushed
1b4d47b7a3e7: Pushed
a3a67812fd2d: Pushed
cb6798486542: Pushed
cb0076c98b2c: Pushed
8f0b8fdd795f: Pushed
todofunction-4014533baa38-v1: digest: sha256:105bc7c6ce5aadd80e2c6e2fb96a64f2dde41a24600499fc442ac64f7f7f52f0 size: 2623
Then SAM will start initiating deployment
Initiating deployment
=====================
TodoFunction has no authentication.
TodoFunction has no authentication.
Uploading to hapijs-todoapp/1599f63c1d296a53c88fc482c7d09a71.template 1413 / 1413 (100.00%)
Waiting for changeset to be created..
CloudFormation stack changeset
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation LogicalResourceId ResourceType Replacement
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Add ServerlessHttpApiApiGatewayDefaultStage AWS::ApiGatewayV2::Stage N/A
+ Add ServerlessHttpApi AWS::ApiGatewayV2::Api N/A
+ Add TodoFunctionPetstorePermission AWS::Lambda::Permission N/A
+ Add TodoFunctionRole AWS::IAM::Role N/A
+ Add TodoFunctionRootPermission AWS::Lambda::Permission N/A
+ Add TodoFunction AWS::Lambda::Function N/A
+ Add TodoTable AWS::DynamoDB::Table N/A
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Then after completing the deployment, AWS SAM will return an output of the endpoint URL like this.
Outputs
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Key TodoApi
Description API Gateway endpoint URL for Prod stage for Todo function
Value https://fr9mddpdg7.execute-api.ap-southeast-1.amazonaws.com/
We'll initiate testing our application using the output endpoint URL https://fr9mddpdg7.execute-api.ap-southeast-1.amazonaws.com/
.
For the next subsequent deployment or after modifying AWS SAM template, you can just run this command.
sam build
sam deploy
Test
To verify the functionality of our Endpoint URL, we can execute the following commands to both send new data and retrieve the corresponding response:
$ curl -k -X POST \
> -H "Content-Type: application/json" \
> -d '{"title":"Deploy and Run Node.js Application on AWS Lambda"}' \
> https://fr9mddpdg7.execute-api.ap-southeast-1.amazonaws.com/todos
{"$metadata":{"httpStatusCode":200,"requestId":"KDTCSC5G29C07JE6TM0V4QH0VRVV4KQNSO5AEMVJF66Q9ASUAAJG","attempts":1,"totalRetryDelay":0}}
Subsequently, we can retrieve the data we previously posted by executing this command and inspecting the response:
$ curl -k https://fr9mddpdg7.execute-api.ap-southeast-1.amazonaws.com/todos
{"response":[{"id":"1698140034538","iscompleted":false,"title":"Deploy and Run Node.js Application on AWS Lambda"}]}
The above commands demonstrate the successful deployment and execution of our Node.js application on AWS Lambda, connected to an Amazon DynamoDB database.
Cleanup
To remove our serverless application deployed using AWS SAM, execute the following command:
sam delete
sam delete
will delete an AWS SAM application by deleting the AWS CloudFormation stack, the artifacts that were packaged and deployed to Amazon S3 and Amazon ECR, and the AWS SAM template file.
Conclusions
In this article, we discover that we can deploy and execute our Node.js application on AWS Lambda, leveraging the capabilities of the AWS Lambda Web Adapter.
Top comments (0)