Mock AWS Services in Local Development Environment with LocalStack and NodeJS
November 19, 2022 · 9 min · 1848 words · Prakash Bhandari
Table of Contents
I was developing and deploying the applications to dedicated servers, on-premises and shared servers. In 2017, I got an opportunity to work with AWS
for one of the retail online ecommerce web application. Since then primarily, I have been developing AWS based applications.
In my career, I have used many AWS services. Primarily, Route 53, EC2 instances, RDS, SQS, SNS, S3 buckets and so on.
Developing and testing applications in the real AWS account is sometimes time-consuming, costly and has dependency on the internet.
I was looking for an AWS cloud service emulator as an alternative solution to get rid of all these issues.
I found LocalStack as a solution.
In this post I will focus on AWS S3 bucket. I will practically show you how to add LocalStack docker container for NodeJS project. Also, I will demonstrate how to create S3 bucket, list the created bucket names and upload file object to the created S3 buckets.
LocalStack is a cloud service emulator that runs in a single container on your local machine or in your CI environment. With LocalStack, you can run your AWS services like S3 bucket, Lambda functions, SQS, etc entirely on your local machine without connecting to a remote cloud provider. Whether you are testing complex CDK applications or Terraform configurations, or just beginning to learn about AWS services, LocalStack helps speed up and simplify your testing and development workflow.
Basic version of LocalStack supports a growing number of AWS services, like AWS Lambda, S3, Dynamodb, Kinesis, SQS, SNS, and many more.
The Pro version of LocalStack supports additional APIs and advanced features. You can find a comprehensive list of supported APIs on Feature Coverage page.
You can configure LocalStack in two ways. One way is to directly install in your machine. Another way is to run LocalStack inside a container. I always prefer to run inside a docker container.
docker-compose.yaml will create two containers aws-app and aws-app-localstack.
Node app is running inside aws-app container and AWS services are running inside the aws-app-localstack container.
Node App runs at port number 8081: http://localhost:8081/
LocalStacks runs at port number 4566 : http://localhost:4566/
create server.js file in the root of the project and import following packages.
express : To write the APIs. We will not use much for this project
aws-sdk : Official AWS SDK package. We will use it to create S3 bucket, list the created bucket names and upload file object to the created S3 buckets.
crypto : To generate random UUIDs.
and load AWS configuration form config.json file
Create config.json file and place AWS configuration. For now we will add LocalStack configuration.
Add SLEEP_TIME and BUCKET_NAME in the server.js file. crypto.randomUUID() is embeded at the end of
localstack-test-bucket test s3 bucket to generate random/unique bucket everytime.
/**
* List the bucket names
*/functionlists(s3){s3.listBuckets(function(err,data){if(err){console.log("Error",err);}else{console.log("Buckets Lists",data.Buckets);}});}
Write a function to upload file object to the S3 bucket programmatically in the server.js file. We have localstack.png file inside static folder. We will upload this file to the localstack
/**
* Upload file object
*/functionuploadObject(bucketName,s3,filePath,keyName){varfs=require("fs");// Read the file
constfile=fs.readFileSync(filePath);// Setting up S3 upload parameters
constuploadParams={Bucket:bucketName,Key:keyName,// custome file name that your want save as.
Body:file,};s3.upload(uploadParams,function(err,data){if(err){console.log("Error",err);}if(data){console.log("Upload Success",data.Location);}});}
Creat main function where we will be calling all the functions that we created to
create S3 bucket, list bucket and upload files from bucket.
/**
* Main function
*/asyncfunctionmain(){console.log("----------------------STARTED--------------------------- \n\n");awaitsleep(SLEEP_TIME);console.log("Creating Bucket...");create(BUCKET_NAME,S3);awaitsleep(SLEEP_TIME);console.log("Listing Buckets...");lists(S3);awaitsleep(SLEEP_TIME);console.log("Uploading File object to bucket...");uploadObject(BUCKET_NAME,S3,"./static/localstack.png","localstack-feature-image.png");awaitsleep(SLEEP_TIME);console.log("----------------------END--------------------------- \n\n");}
Call main function in the server.js file. So, that it will perform all the S3 operations.
"use strict";constexpress=require("express");constAWS=require("aws-sdk");constcrypto=require("crypto");AWS.config.loadFromPath("./config.json");// Constants
constPORT=8081;constHOST="0.0.0.0";constBUCKET_NAME="localstack-test-bucket-"+crypto.randomUUID();constSLEEP_TIME=3000;/**
* Create S3 service object
*/constS3=newAWS.S3({endpoint:"http://localstack:4566",s3ForcePathStyle:true,});/**
* Utility function to for async & wait
*/functionsleep(ms){returnnewPromise((resolve)=>{setTimeout(resolve,ms);});}/**
* Create bucket
*/functioncreate(bucketName,s3){s3.createBucket({Bucket:bucketName},function(err,data){if(err){console.log("Error",err);}else{console.log("Bucket Location",data.Location);}});}/**
* List the bucket names
*/functionlists(s3){s3.listBuckets(function(err,data){if(err){console.log("Error",err);}else{console.log("Buckets Lists",data.Buckets);}});}/**
* Upload file object
*/functionuploadObject(bucketName,s3,filePath,keyName){varfs=require("fs");// Read the file
constfile=fs.readFileSync(filePath);// Setting up S3 upload parameters
constuploadParams={Bucket:bucketName,Key:keyName,// custome file name that your want save as.
Body:file,};s3.upload(uploadParams,function(err,data){if(err){console.log("Error",err);}if(data){console.log("Upload Success",data.Location);}});}/**
* Main function
*/asyncfunctionmain(){console.log("----------------------STARTED--------------------------- \n\n");awaitsleep(SLEEP_TIME);console.log("Creating Bucket...");create(BUCKET_NAME,S3);awaitsleep(SLEEP_TIME);console.log("Listing Buckets...");lists(S3);awaitsleep(SLEEP_TIME);console.log("Uploading File object to bucket...");uploadObject(BUCKET_NAME,S3,"./static/localstack.png","localstack-feature-image.png");awaitsleep(SLEEP_TIME);console.log("----------------------END--------------------------- \n\n");}/**
* calling main function
*/main();/**
* App
*/constapp=express();app.listen(PORT,HOST,()=>{console.log(`Running on http://${HOST}:${PORT}`);});
You can run project simply running the docker compose command
docker compose up
That’s it !!!
We have successfully created NodeJS app with LocalStack emulator for AWS services. In this post,
we have learned how to create S3 buckets
list created buckets, and upload file objects to the buckets.
For production environment, we just need to change configuration in config.js file and replace endpoint with production endpoint