Sitemap
Bits and Pieces

Insightful articles, step-by-step tutorials, and the latest news on full-stack composable software development

Using SST Components for Lambda Functions

Why You Should Consider SST Components for Lambda Functions

5 min readDec 11, 2024

--

Press enter or click to view image in full size

Serverless computing has revolutionized how developers build applications. AWS Lambda for serverless architectures enables rapid development, reduced costs, and seamless scalability.

However, managing and deploying Lambda functions can become cumbersome without a streamlined framework. Today, there are many frameworks and tools to solve these challenges. SST (Serverless Stack) offers a powerful solution that works best for Lambda in terms of cost and optimization.

Yet, it's not fully complete when structuring the Lambda logic, where Bit components can bridge the gap.

Bit Components powering Composable Architectures

This article explores the benefits of using SST with Bit components for AWS Lambda functions, detailing their impact on development workflows, infrastructure management, and scalability.

It also works well when SST hosts the frontend components in Lambda (e.g. when NextJS + SST is used).

What Are SST Components?

SST Components are building blocks that simplify serverless application development. They provide a unified way to define, manage, and deploy serverless resources such as Lambda functions, APIs, and DynamoDB tables. Unlike traditional IaC (Infrastructure as Code) tools, SST components integrate application code with infrastructure configuration, streamlining the development lifecycle.

The Case for SST and Bit

SST simplifies serverless application development by abstracting AWS infrastructure and focusing on code and deployment efficiency. For example, an SST component can represent a Lambda function with all its configurations (e.g., environment variables, IAM roles, triggers):

import * as sst from "@serverless-stack/resources";

export default function MyStack({ stack }) {
const lambda = new sst.Function(stack, "MyFunction", {
handler: "functions/my-function.handler",
});

stack.addOutputs({
FunctionArn: lambda.functionArn,
});
}

This approach reduces boilerplate and integrates infrastructure management with application logic, improving consistency and developer productivity.

Bit Components: Modularizing Lambda Functions

Bit takes SST’s modularity further by transforming Lambda functions and their dependencies into standalone components. A Bit component encapsulates all logic, configuration, and testing for a Lambda function, enabling it to:

  1. Be Independently Versioned: Each Lambda function or dependency is independently versioned and reusable across other functions.
  2. Live in Multiple Repositories: Components are not tied to a single repository or monorepo. They can be shared across distributed repositories or even across organizations.
  3. Enhance Change Tracking: Changes to a Lambda function or its dependencies are automatically detected and tracked, ensuring teams know all modifications before deployment.
Press enter or click to view image in full size
Example: Lambda function components and other dependencies
  1. Improved Modularity and Testing: Each Bit component is independently testable, making debugging and quality assurance more manageable. This allows testing of the individual units inside the Lambada function logic.

Lambda SST and Bit Components: Modular and Reusable Logic

Reusable components for cross-cutting concerns like sanitization, validation, and authorization are powerful tools in modern serverless development. These components, stored on Bit Platform, are versioned and can be reused across Lambda functions, ensuring consistency and modularity.

Note: Instead of importing from local paths, these components are imported from a Bit organization and namespace, similar to an npm package, where each component has its own lifecycle.

Suppose you need to create two Lambda functions, CreateUser and AuthenticateUser, both reuse the shared components for sanitization, validation, and authorization.

functions/
createUser/
handler.ts
index.ts
authenticateUser/
handler.ts
index.ts
shared/
sanitization/
sanitization.ts
index.ts
validation/
validation.ts
index.ts
authorization/
authorization.ts
index.ts

For example, the Sanitization Component and Validation Component may look as follows.

// # Validation Component
// @file: shared/sanitization/sanitization.ts
export const sanitizeInput = (input: any): any => {
// Example sanitization logic
return {
...input,
sanitized: true,
};
};
// # Sanitization Component
// @file: shared/validation/validation.ts
export const validateInput = (input: any): boolean => {
if (!input || !input.requiredField) {
throw new Error("Validation failed: Missing requiredField");
}
return true;
};

Now, let's look at how we can structure the lambda functions.

// # Create User Lambda Componenent
// @file: functions/createUser/handler.ts
import { sanitizeInput } from "@org.utils/sanitization";
import { validateInput } from "@org.utils/validation";
import { authorizeRequest } from "@org.utils/authorization";
import { createUserInDB } from "@org.business/create-user";

export const handler = async (event: any) => {
// Authorize the request
authorizeRequest(event.headers);

// Parse and sanitize the input
const body = JSON.parse(event.body || "{}");
const sanitizedInput = sanitizeInput(body);

// Validate the sanitized input
validateInput(sanitizedInput);

// Perform user creation logic
const createdUser = createUserInDB(sanitizedInput);

return {
statusCode: 201,
body: JSON.stringify({
message: "User created successfully!",
user: createdUser,
}),
};
};
// # Authenticate User Lambda Component
// @file: functions/createUser/handler.ts
import { sanitizeInput } from "@org.utils/sanitization";
import { validateInput } from "@org.utils/validation";
import { authorizeRequest } from "@org.utils/authorization";

export const handler = async (event: any) => {
// Authorize the request
authorizeRequest(event.headers);

// Parse and sanitize the input
const body = JSON.parse(event.body || "{}");
const sanitizedInput = sanitizeInput(body);

// Validate the sanitized input
validateInput(sanitizedInput);

// Perform authentication logic (mocked for this example)
const isAuthenticated = sanitizedInput.username === "admin" && sanitizedInput.password === "password";

if (!isAuthenticated) {
return {
statusCode: 401,
body: JSON.stringify({ message: "Authentication failed" }),
};
}

return {
statusCode: 200,
body: JSON.stringify({
message: "Authentication successful",
token: "fake-jwt-token",
}),
};
};

Breaking the Lambda function into components makes the overall function robust. It speeds up the development speed since we can interest fast on business logic, even without deploying the code into the AWS cloud.

  1. Modular Business Logic: Components like createUserInDB encapsulate business-specific logic, ensuring a clear separation of concerns.
  2. Cross-Cutting Component Reuse: Authorization, validation, and sanitization logic are consistent across functions, improving maintainability.
  3. Dependency Management with Bit:
  • Bit tracks dependencies across functions, ensuring the impact of changes to shared components is visible.
  • All reusable components are imported via the Bit Cloud registry (e.g., @org.utils/sanitization).

Conclusion

Overall, this structure promotes scalability and maintainability for complex Lambda-based serverless applications.

Get Ashan Fernando’s stories in your inbox

Join Medium for free to get updates from this writer.

Structuring Lambda functions as SST components and more granular business logic components with Bit helps to manage dependency management. You can:

  • Centralize and reuse cross-cutting logic like sanitization, validation, and authorization.
  • Manage complex dependency graphs.

Thank you for reading! Cheers!

--

--

Ashan Fernando
Ashan Fernando

Written by Ashan Fernando

Solutions Architect and a Content Specialist. For more details find me in Linkedin https://www.linkedin.com/in/ashanfer/

Bits and Pieces
Bits and Pieces

Published in Bits and Pieces

Insightful articles, step-by-step tutorials, and the latest news on full-stack composable software development