A couple of years ago, I wrote an article on freeCodeCamp about testing serverless applications in AWS. In that article, I explained the technical aspects of testing a serverless application formed of an API Gateway, a Lambda function and a DynamoDB table. I talk about how to test the function using unit tests, the DB with a bash script, and the overall app (i.e. the API endpoint) with e2e tests. However, there's an important piece that I missed in that article. Where does all of the testing happen? I assumed that testing occurs on the cloud, except for unit tests.
A compelling question frequently arises in my enthusiastic discussions about serverless technology: How can we conduct local testing?
I typically encourage the usage of mocks, but I think it's more suitable for testing in isolation (e.g. testing a single component of your app, mocking external services it integrates with). I am not a fan of Emulators; my experience with these tools that mimic a cloud service has been brittle, mainly due to setup complexity and parity with the real service used.
A few years ago, I failed a technical interview because I did not offer a way to start and test a serverless app in a local environment. There's a need for a mindset change when working with serverless resources; some might disagree. That is going to be a discussion for a different day. For this post, I wanted to explore how to bridge the gap between cloud-based testing and the convenience of local development.
Photo by Ben Mack
I read about SST (Serverless Stack) and the live Lambda feature it offers. The SST Docs mention:
Live Lambda Development or Live Lambda is feature of SST that allows you to debug and test your Lambda functions locally, while being invoked remotely by resources in AWS. It works by proxying requests from your AWS account to your local machine.
Let's explore the Live Lambda feature of SST. This will be an opportunity to set up an app with SST and evaluate the developer experience.
Building an app with SST
SST relies on AWS CDK to write the infrastructure code using a set of programming languages (We'll use TypeScript in our example). The CDK converts that code into CloudFormation templates behind the scenes.
SST offers a few constructs built on top of AWS CDK:
-
sst build
runscdk synth
internally. This converts the code to CloudFormation templates -
pnpm sst dev
orpnpm sst deploy
runscdk deploy
. This submits the templates to CloudFormation, which creates the stacks and their defined resources.
Let's create an SST project:
npx create-sst@latest
? Project name demo-sst
✔ Copied template files
Next steps:
- cd demo-sst
- npm install (or pnpm install, or yarn)
- npm run dev
The infrastructure code is listed under /stacks
, and the application code is listed under /packages
. Notice that under MyStack.ts
, an event bus and a few API routes are defined. Feel free to remove these, keeping the following only:
import { StackContext, Api } from 'sst/constructs';
export function API({ stack }: StackContext) {
const api = new Api(stack, 'api', {
routes: {
'GET /': 'packages/functions/src/lambda.handler',
},
});
stack.addOutputs({
ApiEndpoint: api.url,
});
}
This code defines a GET API endpoint that will invoke the lambda function.
Feel free to delete the folders and files that aren't needed under packages
.
Once the app is started and deployed, you will get the API URL, which we specified as an output in the /stacks/MyStack.ts
file. Requesting this API will return the value define in the /packages/functions/src.lambda.ts
file. Change the returned value there and submit a new request to the API endpoint. Notice how you got the new value.
This is the SST Live Lambda. Without the long loop of deploying your changes to AWS, you get to execute your local Lambda function from the API Gateway already deployed in AWS.
SST mainly creates a WebSocket and proxies requests from Lambda functions to your local machine. You can find more details in the SST docs.
Here's how it looks like:
How is this different from running your Lambda using a NodeJS worker?
Even though the functional behaviour of your Lambda code might be similar (i.e. experiencing similar behaviour of the Lambda function), running a Live Lambda offers a fully integrated environment where the Lambda configuration is as close to production since the whole environment is already running in the cloud. That provides better confidence over a local setup where you rely on AWS creds to do the execution. The integration allows you to test integrations with other AWS services such as API Gateway, Event Bridge, S3, etc. This offers a great win over setting up emulators on your local.
The next step would be to build a larger-scale project that integrates with services from AWS, such as S3, SQS, Event-Bridge, etc. How do you build a serverless app? and what's your dev experience like?
Top comments (0)