NodeJS Express and AWS Lambda Functions
Lambda functions, nodejs and github actions series
In my previous article I wrote about Lambda Function, NodeJS and GitHub Actions. Now, I will share a second article related to "Running a Lambda Express API".
This article assumes that you are familiar with Lambda Function and GitHub Actions. If you are new to Lambda or Github itself, refer first to my previous article call Lambda Functions Challenge.
For this article, you will need:
AWS credential for deploy and execution access.
GitHub Repository
Repository secret with AWS credential loaded: Repository Settings -> Secrets and Variables -> Actions -> New repository secret (we need it for deploy lambda function).
Working with NodeJS
Create express API
Use the npm command to create a new project:
npm init --yes # this will trigger automatically populated initialization with default values
After that, we are going to install express framework to build the REST API:
npm install express
Next step, create a new app directory and inside create an app.js file. The project should look like this:
In the app.js file we add the express server setup:
const express = require('express')
const app = express();
const port = process.env.PORT || 3000;
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.get('/api/v1/hello', (req, res) => {
res.send({ app: 'aws-lambda-expressjs-nodejs', version: '1.0.0' });
});
app.listen(port, () => console.log(`Listening on: ${port}`));
Execute the following command to check that everything is ok:
node app/app.js
Then, visit the url http://127.0.0.1:3000/api/v1/hello and you should get the response bellow:
{
"app": "aws-lambda-expressjs-nodejs",
"version": "1.0.0"
}
Convert our express api to "Lambda Express REST API"
We need to install serverless-http our "serverless wrapper" to make our express app ready to deploy on Lambda Environment:
npm install serverless-http
This module allows you to 'wrap' your API for serverless use. No HTTP server, no ports or sockets. Just your code in the same execution pipeline you are already familiar with
Now, we are going to add the serverless module and creating a handler for lambda function:
const express = require('express')
// include the serverless-http module
const serverless = require('serverless-http');
const app = express();
const port = process.env.PORT || 3000;
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.get('/api/v1/hello', (req, res) => {
res.send({ app: 'aws-nodejs-lambda-function', version: '1.0.0' });
});
// comment express server
//app.listen(port, () => console.log(`Listening on: ${port}`));
// add the handler for our lambda function
module.exports.handler = serverless(app);
From now on, our project is ready to deploy in AWS Lambda environment but before we need to change the function runtime settings and add a trigger type AWS API Gateway (REST).
Runtime Settings
We should be set the handler value with "app/app.handler" since our handler function is located under de directory "app" in "app.js" file.
Go to "Run Time settings" and set the handler value with app/app.js
API Gateway (REST API)
Create a trigger for add an API Gateway that route HTTP requests to our Lambda function:
Now, we are going to create a resources in our API Gateway. Go to the API Gateway page, click on Action button and select "Create Resource":
On "resource path" configuring /{proxy+} as a proxy resource catches all requests to its sub-resources.
Right after that, create an integration between api gateway and lambda function:
The Api Gateway Resources should look like this:
At this point, we need to deploy a new version of our Api. Go to the Action button and select deploy option:
In the stage editor you can find de invoke url (we need it in the final step):
Create a local environment execution
We need a local environment for develop new features and test the code in our machine. So, in the "scripts" section located the package.json file, add the following command to execute the project as Local Environment using express server:
"local": "APP_ENV=local node app/app.js",
We passed an APP_ENV environment variable with a value equal "local" for set running express out of serverless module.
Now, we will edit the app.js file and make the following changes:
...
if (process.env.APP_ENV === 'local') {
app.listen(port, () => console.log(`Listening on: ${port}`));
} else {
module.exports.handler = serverless(app);
}
Execute the following command to check that everything is ok:
npm run local
Then, visit the url http://127.0.0.1:3000/api/v1/hello and you should get the response bellow:
{
"app": "aws-lambda-expressjs-nodejs",
"version": "1.0.0"
}
Pipeline
For this article we are going to create a pipeline using GitHub actions. We need to add a main.yml file under the path ".github/workflows" with the content bellow:
\ You should provide the AWS Lambda Function name in the step "Deploy"*
name: Deploy
on:
push:
branches:
- master
jobs:
deploy-lambda:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '16'
- name: Install dependencies
run: npm ci --ignore-scripts
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1-node16
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Deploy
run: |
zip -r deploy.zip .
aws lambda update-function-code --function-name=your-lambda-function --zip-file=fileb://deploy.zip
Now we are all set to deploy our application. So, commit and push the changes to the repository and the pipeline starts automatically. You can see the progress in the Actions option:
Now, is time to test our lambda function. Go to the browser, paste de api gateway url and add our express api path:
https://xxxxxx.execute-api.us-east-1.amazonaws.com/default/api/v1/hello
You should get the response bellow:
}
"app": "aws-lambda-expressjs-nodejs",
"version": "1.0.0"
}
Well done, we have a express js running over lambda function 👏 👏
Conclusion
You can get the source files from my GitHub repository and my previous article here
For this very simple example, we used the default values provided from AWS Console. We didn't talk about Api Gateway security (token, certificates, api key, etc) and Lambda functions deployment packages size as well; If our project is larger than 50 MB, we need a extra integration with S3 Bucket.
Fortunately for us, Lambda functions and api gateway has a lot of features and it is well-documented.
Resources
https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-deploy-api.html
https://www.npmjs.com/package/serverless-http
https://www.npmjs.com/package/express
htps://www.npmjs.com/package/express
https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-package.html
https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-package.html
https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html