This test app implements a NodeJS REST API for running in Lambda that can also be tested locally. It uses the express and serverless-http node packaged modules. This is based on the excellent tutorial.
-
Create a folder (e.g.
lambda-express-rest-api) and cd inside -
Create a
package.jsonfile:{ "name": "lambda-express-rest-api", "version": "1.0.0", "type": "module", "dependencies": { "express": "^4.18.2", "serverless-http": "^3.2.0" } } -
Install the dependencies.
npm install -
Create an
app.mjsfile that defines some simple routes/methods:import express from 'express'; const app = express(); app.use(express.json()); app.get('/hello', (req, res) => { res.json({ message: 'Hello from Express on Lambda!' }); }); app.post("/echo", (req, res) => { res.setHeader('content-type', 'application/json'); res.json({ youSent: req.body }); }); app.get('/async', async (req, res) => { await new Promise(resolve => setTimeout(resolve, 1000)); res.json({ message: 'Async operation completed' }); }); export default app;
-
Create a
local.mjsfileimport app from './app.mjs'; const port = process.env.PORT || 3000; app.listen(port, () => { console.log(`Local server running on http://localhost:${port}`); });
-
Run using
node local.mjs -
Test Using Curl or Postman
curl 'http://localhost:3000/hello'with response:
{ "message": "Hello from Express on Lambda!" }curl --location 'http://localhost:3000/echo' \ --header 'Content-Type: application/json' \ --data-raw '{ "id": 1, "first_name": "Kellen", "last_name": "Tunder", "email": "ktunder0@nifty.com", "gender": "Female", "ip_address": "74.254.10.244" }'
with response:
{ "youSent": { "id": 1, "first_name": "Kellen", "last_name": "Tunder", "email": "ktunder0@nifty.com", "gender": "Female", "ip_address": "74.254.10.244" } }curl 'http://localhost:3000/async' --header 'Content-Type: application/json'
with response:
{ "message": "Async operation completed" }
-
Create an index.mjs Lambda Handler file:
import serverless from 'serverless-http'; import app from './app.mjs'; export const handler = serverless(app);
-
Create a zip archive of your files:
zip -r deployment.zip node_modules app.mjs index.mjs package.json -
Create a Lambda function (e.g.
lambda-express-rest-api) with Node.js 22 or later and upload the deployment.zip file
-
Enable Function URL with Auth type
NONEtemporarily to test your APIs -
Use CURL to test your API's
curl --location 'https://hrgxowogjitvuh4rxp24jouweu0svrhz.lambda-url.us-east-1.on.aws/hello'curl 'https://hrgxowogjitvuh4rxp24jouweu0svrhz.lambda-url.us-east-1.on.aws/echo' \ --header 'Content-Type: application/json' \ --data-raw '{ "id": 1, "first_name": "Kellen", "last_name": "Tunder", "email": "ktunder0@nifty.com", "gender": "Female", "ip_address": "74.254.10.244" }'
curl 'https://hrgxowogjitvuh4rxp24jouweu0svrhz.lambda-url.us-east-1.on.aws/async' --header 'Content-Type: application/json'
with same responses as before
- Create a REST API in the AWS API Gateway
- Create a resource (hello) and a method (GET) and link to your lambda function
- Deploy to a stage
- Now, you can access your Express.js application through the API Gateway endpoint
curl --location 'https://r86cp1oowh.execute-api.us-east-1.amazonaws.com/prod/hello' - Add API Key authentication to secure your API
- You can delete the Function URL created above
Instead of zipping the project and uploading to Lambda, you can create a docker image and upload it to AWS ECR and use the image when creating a lambda function.
You need the aws and docker cli's installed and working.
-
Create a Dockerfile
FROM public.ecr.aws/lambda/nodejs:20 # Set working directory WORKDIR /var/task # Copy package files and install dependencies COPY package*.json ./ RUN npm install # Copy app code COPY . . # Specify the Lambda function handler CMD ["index.handler"]
-
Use the Dockerfile to build a Docker image
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws docker buildx build --platform linux/amd64 -t lambda-express-rest-api-docker .
-
Tag the image
Create a local environment variable as follows:
ECR_URL=<aws_account_id>.dkr.ecr.<region>.amazonaws.com/<repository_name>
and tag your image:
```bash
ECR_URL=411427429079.dkr.ecr.us-east-1.amazonaws.com/lambda-express-rest-api-docker
docker tag lambda-express-rest-api-docker:latest $ECR_URL:latest
```
-
Create ECR Repo
aws ecr create-repository --repository-name lambda-express-rest-api-docker --region us-east-1
-
Push to ECR
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin $ECR_URL docker push $ECR_URL:latest
-
Create a lambda function and select Container image and select the image you just uploaded
-
Enable Function URL as above and test your API's
-
Configure AWS API Gateway as above and test your API's
Add Axios support to make external API calls to REST API's. In this example, we'll call the NASA Astronomy Picture of the Day API.
-
Add axios npm
npm i axios -
Add an Axios import to app.mjs
import express from 'express';
-
Add a new route to app.mjs
app.get('/apod', async (req, res) => { const response = await axios.get('https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY'); res.json(response.data); });
-
Run and test locally
curl --location 'http://localhost:3000/apod' --header 'Content-Type: application/json'
with response:
```json { "date": "2025-04-21", "explanation": "Is this one galaxy or two? Although it looks like one, the answer is two. One path to this happening is when a small galaxy collides with a larger galaxy and ends up in the center. But in the featured image, something more rare is going on. Here, the central light-colored elliptical galaxy is much closer than the blue and red-colored spiral galaxy that surrounds it. This can happen when near and far galaxies are exactly aligned, causing the gravity of the near galaxy to pull the light from the far galaxy around it in an effect called gravitational lensing. The featured galaxy double was taken by the Webb Space Telescope and shows a complete Einstein ring, with great detail visible for both galaxies. Galaxy lenses like this can reveal new information about the mass distribution of the foreground lens and the light distribution of the background source.", "hdurl": "https://apod.nasa.gov/apod/image/2504/GalaxiesLens_Webb_1146.jpg", "media_type": "image", "service_version": "v1", "title": "Galaxy Lenses Galaxy from Webb", "url": "https://apod.nasa.gov/apod/image/2504/GalaxiesLens_Webb_960.jpg" } ```
In this example, we'll add an AWS Translate method.
-
Add @aws-sdk/client-translate npm
npm i @aws-sdk/client-translate -
Add an @aws-sdk/client-translate import to app.mjs and declare a client
import { TranslateClient, TranslateTextCommand } from "@aws-sdk/client-translate"; const client = new TranslateClient({ region: "us-east-1" });
-
Add a new route to app.mjs
app.get('/translate', async (req, res) => { const input = { Text: req.query.text, SourceLanguageCode: req.query.sourcelanguage, TargetLanguageCode: req.query.targetlanguage, Settings: { Formality: "INFORMAL", Profanity: "MASK", Brevity: "ON", } }; const command = new TranslateTextCommand(input); const ttResponse = await client.send(command); const response = { "SourceText": input.Text, "SourceLanguageCode": ttResponse.SourceLanguageCode, "TargetLanguageCode": ttResponse.TargetLanguageCode, "TranslatedText": ttResponse.TranslatedText } res.json(response); });
-
Test locally
curl --location 'http://localhost:3000/translate?text=Hello&sourcelanguage=en&targetlanguage=ja' --header 'Content-Type: application/json'
with response:
{ "SourceText": "Hello", "SourceLanguageCode": "en", "TargetLanguageCode": "ja", "TranslatedText": "こんにちは" } -
When you deploy to Lambda make sure your Service Role supports
Translate: TranslateText



















