Testing Serverless Applications Locally With LocalStack
profile picture Srinu Madhav Vysyaraju
6 min read Mar 12, 2023

Testing Serverless Applications Locally With LocalStack

Introduction

Serverless applications are a popular way to build and deploy applications and microservices. They allow you to run your code in the cloud without the need to manage infrastructure, and they can be a cost-effective way to scale your application.

However, testing and debugging serverless applications can be a challenge, especially if you are developing and testing in the cloud. This is where LocalStack comes in. LocalStack is a tool that allows you to emulate a number of AWS services locally, including Lambda functions, S3 buckets, and more. This can be incredibly useful for developing and testing serverless applications, as it allows you to test your functions and their integrations with other AWS services without having to deploy them to the cloud.

In this post, we’ll walk through the process of setting up LocalStack and using it to test a serverless application locally. Prerequisites:

  • Python 3.7 or above
  • Pip
  • Docker
  • Serverless Framework

Localstack

LocalStack is a cloud service emulator that runs in a single container on your laptop or in your CI environment. With LocalStack, you can run your AWS applications or Lambdas 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.

Supported Services :

Local Stack supports most of the commonly used services such as Lambda, S3, Dynamo DB, SQS, EC2, Cognito, and many more, a full list of the services can be found at Supported Services.

Setting up LocalStack :

Let us install Localstack CLI as the first step of our journey towards debugging the application locally

  1. The easiest way to install localstack CLI is through pip:
python3 -m pip install localstack

Then Use below command to start the local stack on your system, which will eventually spin up a container.

localstack start
  1. You can also install localstack through Docker, You can simply start localstack using
docker run --rm -it -p 4566:4566 -p 4510-4559:4510-4559 localstack/localstack
  1. If you want to manually manage the docker image you can use Local Stack Docker File and use the following command to build and run the container image.
docker-compose up

Testing your serverless application

Once LocalStack is running, you can use it to test your serverless application. To do this, you will need to update your application code to use the local endpoint URLs provided by LocalStack. For example, you might update the AWS_REGION and AWS_LAMBDA_FUNCTION_NAME environment variables in your application to point to the local endpoint for the Lambda service.

You can then test your application using the usual debugging tools, such as print statements and debugging tools like pdb. Keep in mind that there may be some differences between testing locally and in the cloud, so it’s a good idea to test your application both locally and in the cloud to ensure it is working correctly in both environments.

For this post, We are using the code in this GitHub repo that uploads images to s3 using presigned URLs, Whenever a request comes to the lambda, it gets the presigned URL from s3 and then we can upload the image to the presigned URL even if the bucket is private

While declaring we should handle configuring the services to use local endpoints instead of the original endpoints.

Given below is an example used in the handler.js file

if (process.env.NODE_ENV === "local") { // ? used for local development
  s3 = new AWS.S3({
    endpoint: "http://localhost:4566",
    s3ForcePathStyle: true,
  }); 
}

Let us go through the handler.js file to understand what’s happening :

// handler.js
const AWS = require("aws-sdk");
const express = require("express");
const serverless = require("serverless-http");
require('dotenv').config()
const app = express();

app.use(express.json());
let s3 = new AWS.S3();

if (process.env.NODE_ENV === "local") { // ? used for local development
  s3 = new AWS.S3({
    endpoint: "http://localhost:4566",
    s3ForcePathStyle: true,
  }); 
}

// * Returns signed URL from S3 *
const s3helper = async (name) => {
  const Key = `${name}.jpeg`;
  const s3Params = {
    Bucket: process.env.IMAGE_UPLOAD_BUCKET,
    Key,
    Expires: ~~process.env.SIGNED_URL_EXPIRATION_SECONDS,
    ContentType: "image/jpeg",
    ACL: "public-read",
  };
  const uploadURL = await s3.getSignedUrlPromise("putObject", s3Params);
  let data = {
    Key,
    uploadURL,
  };
  return data;
};

app.get("/upload-url", async (req, res) => {
  try {
    const name = req.query.name;
    if(!name) return res.status(400).json({ msg: "Bad Request: Missing name" });
    const data = await s3helper(name);
    return res.status(200).json(data);
    // ? url = `http://localhost:4566/${process.env.IMAGE_UPLOAD_BUCKET}/${Key}` This is the url where the uploaded image would be available
  } catch (error) {
    return res.status(500).json({ msg: "couldn't get upload URL" });
  }
});

app.use((req, res, next) => {
  return res.status(404).json({
    error: "Not Found",
  });
});

module.exports.handler = serverless(app);

In the handler.js file, we can see an endpoint /upload-url which accepts a name as query parameter and passes it to function s3helper, which uses the name as input parameter for s3 query and get the pre-signed URL from s3 bucket and it will return an object containing pre-signed URL and a key.

To create a bucket offline using localstack use the following command :

awslocal s3api create-bucket --bucket localstackbucket

In the .env file, add the env variables as used in the handler.js file

Once localstack starts running, since this uses a serverless framework you can use the following command to start the offline server

serverless offline 

Now you can use postman or curl to test the API and the response for presigned url which is generated from the locally created bucket.

Stopping LocalStack

When you are finished testing, you can stop the LocalStack service by running the following command localstack stop or use docker kill <CONTAINERID> if you have used docker to start localstack or use docker-compose down if you used docker-compose .

Conclusion

Testing serverless applications locally using LocalStack can be a great way to speed up development and reduce costs. It allows you to test your functions and their integrations with other AWS services without having to deploy them to the cloud, and it can help you catch and fix issues early in the development process.

Give LocalStack a try in your own development and testing workflow, and see how it can help you build and deploy better serverless applications.

References:

service category

Innovate faster, and go farther with serverless-native application development. Explore limitless possibilities with AntStack's serverless solutions. Empowering your business to achieve your most audacious goals.

Build with us

Author(s)

Your Digital Journey deserves a great story.

Build one with us.

Recommended Blogs

cookie

These cookies are used to collect information about how you interact with this website and allow us to remember you. We use this information in order to improve and customize your browsing experience and for analytics and metrics about our visitors on this website.

If you decline, your information won’t be tracked when you visit this website. A single cookie will be used in your browser to remember your preference not to be tracked.

Build With Us