Sitemap
Bits and Pieces

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

Follow publication

Mastering AWS Lambda: 5 Essential Design Patterns for Developers

8 min readJun 18, 2024

--

1. Make Lambda Code and Handler Composable

Composability involves creating software applications from independent, reusable components, each encapsulating its dependencies and distinct functionality. Then, these components (building blocks) can be combined to build more complex applications.

// @file: date-lambda.ts

import { APIGatewayProxyHandler } from 'aws-lambda';
import { dateUtil } from '@bit-pulumi-lambda/demo.utils.date-util'

export const handler: APIGatewayProxyHandler = async () => {
const dateType = process.env.DATE_TYPE || "";
const message = `Hey!, ${dateType} is ${dateUtil(dateType)}`;

return {
statusCode: 200,
body: JSON.stringify({ message }),
};
};
// @file: date-lambda-spec.ts

import { APIGatewayProxyResult } from 'aws-lambda';
import { handler } from './date-lambda';
import { format } from 'date-fns';

describe('Lambda Handler', () => {
it('should return a formatted message with the current date when DATE_TYPE is "today"', async () => {
// Mock the environment variable
process.env.DATE_TYPE = 'today';

// Get the expected date
const expectedDate = format(new Date(), 'yyyy-MM-dd');

// Expected message
const expectedMessage = `Hey!, today is ${expectedDate}`;

// Call the handler
const result = (await handler({} as any, {} as any, {} as any)) as APIGatewayProxyResult;

// Assert the response
expect(result.statusCode).toBe(200);
expect(result.body).toBe(JSON.stringify({ message: expectedMessage }));
});
// ...

2. Use Lambda Env Variables to Pass Operational Parameters

// @file: count-lambda.ts

import { APIGatewayProxyHandler } from 'aws-lambda';
import AWS from 'aws-sdk';

export const handler: APIGatewayProxyHandler = async (event) => {
// Initialize the DynamoDB DocumentClient
const docClient = new AWS.DynamoDB.DocumentClient();
const countTable = process.env.COUNT_TABLE;

// ...
const getResult = await docClient.get({
TableName: countTable,
Key: { sessionId: userIp },
}).promise();

// ...
}
// @file: api-gateway.ts

import * as apigateway from "@pulumi/aws-apigateway";
import bitpulumi from "@bit-pulumi-lambda/demo.awsx.lambda";
import { countTable } from "@bit-pulumi-lambda/demo.dynamodb.count-table";

export function apiRoutes(endpointName: string) {
const api = new apigateway.RestAPI(endpointName, {
routes: [
{
path: "/api/count",
method: "GET",
eventHandler: new bitpulumi.awsx.Lambda(
"count-lambda",
require.resolve("@bit-pulumi-lambda/demo.lambdas.count-lambda"),
{
environment: {
variables: { COUNT_TABLE: countTable.name }, // Optional environment variables
},
}
),
},
// Other routes ...
]
}

3. Use Realtime CloudWatch Log Stream

Running Pulumi Realtime Logs in a New Terminal

4. Bundle your Lambda Function

5: Adjust your Lambda Configuration (Don’t stick to the defaults)

 // Following is bad since it grants 'Delete User" action over all the resources
iam:
role:
name: custom-role-name
path: /custom-role-path/
statements:
- Effect: 'Allow'
Resource: '*'
Action: 'iam:DeleteUser'

Conclusion

--

--

Bits and Pieces

Published in Bits and Pieces

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

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/

Responses (3)