Exploring the Future of Serverless with Sheen Brisals: Why It's Becoming the New Norm
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
- 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
- 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
- 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.