Introduction
In my recent project, I built a blog website from scratch, covering Infrastructure, Backend, and even Frontend. It was a big project with everything made custom. That project, combined with other projects I did in the past, revealed two problems:
- defining boundaries between infrastructure and application code
- the inadequacy of my utility toolbox for certain use cases
Now, these challenges find resolutions in two βοΈ handy tools:
- SST
- Middy
This first part delves into SST, exploring its functionality and setting up a project.
β οΈNote: Middy will be covered in the second part, and the third part unveils the open sourcing of my Newsletter infrastructure built with Typescript using SST and Middy.
SST
SST acts as an Infrastructure As Code tool, wrapping AWS CDK while enhancing it with features tailored for building not only backend but also Server Side Applications like Svelte, Next.js, Solid, etc.
User-Friendly CDK Constructs: Say goodbye to complexity. SST provides optimized constructs for serverless apps. Want your Next.js Website? Just 1 line, that's it.
Live Lambda Development (LLD): Your Instant Lambda Upgrade! Develop in real-time with instant Lambda function updates. No more waiting, code in the cloud within seconds. And the best part? SST seamlessly syncs your local and remote functions. Ever thought, "Great, now I have to dive into CloudWatch logs every time I call a function"? Not anymore! SST streams all logs to your local terminal. Convenient, right? Let's dive into the magic behind this cool feature.
Live Lambda Development
SST uses AWS IoT over WebSocket to bridge the connection between your machine and the AWS Lambda function. But how does this work?
- Execute "sst dev" to deploy a "mock" version of your infrastructure, transforming your Lambda functions into stubs (a simpler version).
- A local WebSocket client starts up and links up with your AWS account.
- When a Lambda function in your app gets used, it sends out an event with the function's request.
- The local WebSocket client gets this event, says it got the request.
- It runs the local function (like a mini version) and then sends out another event with the function's response.
- The stub Lambda function receives the event and responds with the answer, and voila!
Moreover, it's significantly faster than CDK Watch and SAM Accelerate (SST claims 50-100x faster).
I'll be honest; I was a bit skeptical initially. I really wanted to test AWS Lambda functions on my machine because I had always found myself comfortable that way. Oh boy, what I would have missed! After experiencing Live Lambda Development, I was genuinely amazed. No need to mock every AWS service in my environment. That's when I fell in love with this functionality.
Weighing the Pros and Cons
Let's see what are the major pros and cons of SST
Pros
- Live Lambda Development for real-time updates during development
- Higher-level serverless constructs with the flexibility to add custom CDK parameters when necessary
- Engage with a lively community on Discord and Slack
- Effortlessly reference resources across stacks
Cons
- Primarily tailored for AWS Lambda, web applications, and serverless scenarios. For more complexity/enterprise, consider using Terraform or CDK, ideal for complex infrastructures
- Keep in mind, it doesn't support multi-region stacks. If you're venturing into a multi-region serverless stack, your might need to find some workarounds
Setting Up SST
Let's kick things off by initializing the project:
npx create-sst@latest --template=examples/rest-api-dynamodb cd my-sst-app
It's as simple as that! Now, let's quickly go over what just happened:
- sst.config.ts: This file serves as your configuration hub for every stack you deploy. Here's a peek at how I prefer to set it up:
export default { config (_input) { return { name: 'newsletter-backend', region: 'eu-central-1', stage: _input.stage } }, async stacks (app) { app.setDefaultFunctionProps({ ... }) Tags.of(app).add('env', app.stage) Tags.of(app).add('deploy', 'sst') Tags.of(app).add('project', app.name) await app.stack(DatabaseStack) app.stack(EmailStack) app.stack(AlertingStack).stack(SchedulerStack).stack(ApiPermissionStack).stack(ApiStack) } } satisfies SSTConfig
By setting it up this way, you can establish default parameters for every lambda function and seamlessly add tags to your entire infrastructure. And hey, notice the async-await? That's right, deploy stacks in parallel or await others when needed.
stacks/MyStack.ts: This is where your infrastructure takes shape. You can have as many stacks as you want, all in TypeScript. Check out the example API in here. Yep! Is that simple to build and deploy serverless infrastructure.
packages/: Inside, you'll find two folders, core for all your business logic and functions where your AWS Lambda function code resides.
Fantastic! Now, the next steps, it's time to build our application:
npm install npm init @eslint/config
Of course, we're adding a linter. We can't just run wild without something keeping us in check, right? π Once ESLint is configured, your infrastructure is ready to make its cloud debut:
npx sst dev
And there you have itπͺ! Watch as your application is built and a "mock" version is deployed directly to the cloud. Once done, grab the URL, paste it into Postman, and give it a spin.
Conclusion
Congratulations! You've just laid the solid foundation of your serverless infrastructure. Now, it's time to roll up your sleeves and build something exciting. Get hands-on with the tool, and trust me, you're in for a lovely ride.
And the excitement doesn't end here! In the next part, we'll level up by adding Middy as our handler middleware πͺ
If you enjoyed this article, please let me know in the comment section or send me a DM. I'm always happy to chat! βοΈ
Thank you so much for reading! π Keep an eye out for more AWS-related posts, and feel free to connect with me on LinkedIn π https://www.linkedin.com/in/matteo-depascale/.
References
Disclaimer: opinions expressed are solely my own and do not express the views or opinions of my employer.