Skip to content

Usage patterns

Powertools for AWS Lambda (TypeScript) is a collection of utilities designed to help you build serverless applications on AWS.

The toolkit is modular, so you can pick and choose the utilities you need for your application, but also combine them for a complete solution for your serverless applications.

Patterns

Many of the utilities provided can be used with different patterns, depending on your preferences and the structure of your code.

Class Method Decorator

If you prefer writing your business logic using Object-Oriented Programming (OOP) and TypeScript Classes, the Class Method decorator pattern is a good fit. This approach lets you decorate class methods with Powertools utilities, applying their functionality with minimal code changes.

This pattern works well when you want to integrate Powertools for AWS into an existing codebase without significant refactoring and with no additional runtime dependencies.

Note

This approach relies on TypeScript's experimental decorator feature, see TypeScript Settings for more information.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import type { LambdaInterface } from '@aws-lambda-powertools/commons/types';
import { Logger } from '@aws-lambda-powertools/logger';
import { Metrics } from '@aws-lambda-powertools/metrics';
import { Tracer } from '@aws-lambda-powertools/tracer';
import type { Context } from 'aws-lambda';

const logger = new Logger();
const tracer = new Tracer();
const metrics = new Metrics();

class Lambda implements LambdaInterface {
  @tracer.captureLambdaHandler()
  @logger.injectLambdaContext()
  @metrics.logMetrics()
  async handler(_event: unknown, _context: Context) {
    // Your business logic here
  }
}
const lambda = new Lambda();
export const handler = lambda.handler.bind(lambda);

All our decorators assume that the method they are decorating is asynchronous. This means that even when decorating a synchronous method, they will return a promise. If this is not the desired behavior, you can use one of the other patterns.

Middy.js Middleware

If your existing codebase relies on the Middy.js middleware engine, you can use the Powertools for AWS Lambda (TypeScript) middleware to integrate with your existing code. This approach is similar to the Class Method decorator pattern but uses the Middy.js middleware engine to apply Powertools utilities.

Note

We guarantee support for Middy.js v4.x through v6.x versions. Check Middy.js docs to learn more about best practices when working with Powertools for AWS middlewares.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import { Logger } from '@aws-lambda-powertools/logger';
import { injectLambdaContext } from '@aws-lambda-powertools/logger/middleware';
import { Metrics } from '@aws-lambda-powertools/metrics';
import { logMetrics } from '@aws-lambda-powertools/metrics/middleware';
import { Tracer } from '@aws-lambda-powertools/tracer';
import { captureLambdaHandler } from '@aws-lambda-powertools/tracer/middleware';
import middy from '@middy/core';

const logger = new Logger();
const tracer = new Tracer();
const metrics = new Metrics();

export const handler = middy()
  .use(captureLambdaHandler(tracer))
  .use(injectLambdaContext(logger))
  .use(logMetrics(metrics))
  .handler(async (event: unknown) => {
    // Your business logic here
  });

Functional Approach

If you prefer a more functional programming style, you can use the Powertools for AWS Lambda (TypeScript) utilities directly in your code without decorators or middleware. This approach is more verbose but provides the most control over how the utilities are applied.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { Logger } from '@aws-lambda-powertools/logger';
import { Metrics } from '@aws-lambda-powertools/metrics';
import { Tracer } from '@aws-lambda-powertools/tracer';
import type { Context } from 'aws-lambda';

const logger = new Logger();
const tracer = new Tracer();
const metrics = new Metrics();

export const handler = async (event: unknown, context: Context) => {
  logger.addContext(context);
  logger.logEventIfEnabled(event);

  const subsegment = tracer.getSegment()?.addNewSubsegment('#### handler');

  try {
    // Your business logic here
    throw new Error('An error occurred');
  } catch (error) {
    logger.error('Error occurred', { error });
    tracer.addErrorAsMetadata(error);
    throw error;
  } finally {
    subsegment?.close();
    metrics.publishStoredMetrics();
  }
};