Skip to content

Migrating from common-serverless-library

If you are currently using @ns/common-serverless-library, you may want to migrate your code to use Backpack instead.

Do I need to migrate?

Not necessarily — @ns/common-serverless-library and Backpack can be used side by side. However, we've decided to adopt most of its utilities to ensure compatibility and to stay aligned with current best practices.

Here are some key differences in our approach:

  • Utilities are now published in separate packages, allowing for more granular dependency management.
  • Most utility classes support constructor injection, facilitating inversion of control and seamless integration with dependency injection (DI) frameworks.
  • For decorators, we prefer Stage 3 ECMAScript decorators over legacy TypeScript decorators.

AWS Secrets Manager

Updating imports

Utilities for AWS Secrets Manager have been moved to @backpack/aws-secrets-manager, so make sure to install the package and update your imports.

ts
import {
  SecretsManagerService,
  CachedSecretsManagerService
} from '@backpack/aws-secrets-manager';

Changes to SecretsManagerService

  • added constructor injection, make sure to provide a SecretsManagerClient;
  • getSecretValue() is deprecated in favour of getJsonSecret(secretId, { required: false }) (will be removed in a future version)
  • getRequiredSecretValue() is deprecated in favour of getJsonSecret() (will be removed in a future version)
  • batchGetSecretValue() has been removed (barely used in existing projects).

Changes to CachedSecretManagerService

  • renamed from CachedSecretManagerService to CachedSecretsManagerService
  • added constructor injection, make sure to provide a SecretsManagerClient;
  • cacheExpirySeconds moved to options object as cacheExpiryDurationSeconds
  • it now extends SecretsManagerService, make sure to check those changes as well.

Amazon DynamoDB

Updating imports

Utilities for DynamoDB have been moved to @backpack/amazon-dynamodb, so make sure to install the package and update your imports.

ts
import { DynamoDbRepository } from '@backpack/amazon-dynamodb';

Changes to DynamoRepository

  • has been renamed to DynamoDbRepository;
  • constructor injection was added, make sure to provide your own DynamoDBDocumentClient;
  • the tableName method parameter has moved to an options object which can be passed in the constructor;
  • two generic types TItem and TKey were added, reflecting the types of the item and its (composite) key;
  • logging has been made optional, to enable it you only need to pass your logger instance to the constructor options;
  • error logging has changed to debug level, since errors are still propagated;
  • since tableName was moved to the constructor, the existing methods have been deprecated, allowing us to improve naming a bit:
    • putItem(key, tableName) was deprecated in favour of putItem(key, options)
    • getItem(key, tableName) was deprecated in favour of findItemById(key)
    • removeItem(key, tableName) was deprecated in favour of deleteItemById(key)
    • itemExists(key, tableName) was deprecated in favour of itemExistsById(key)
    • getAllItems(tableName) was deprecated in favour of scanAllItems(options)
  • it is now possible to add your mapping functions writeItem() and readItem(), allowing mapping and/or validation with Zod.
  • saveItem(options) was added to perform a Save command.

Changes to DynamoQueryRepository

  • this class has merged with DynamoDbRepository, please review those changes;
  • the existing mapping function has been moved to the option itemMapper.readItem() and is a bit stricter, now accepting a Record<string, unknown> instead of Record<string, any>;
  • queryTable() was deprecated in favour of queryItems(options), which now has an options object accepting all QueryCommandInput parameters.

Amazon SNS

Updating imports

Utilities for SNS have been moved to @backpack/amazon-sns, so make sure to install the package and update your imports.

ts
import { SnsPublisher } from '@backpack/amazon-sns';

Changes to SnsPublisher

  • constructor injection was added, make sure to pass your own SNSClient;
  • the topicArn method parameter has been deprecated and moved to the constructor;
  • logging has been made optional, to enable it you only need to pass your logger instance to the constructor;
  • info and error logging has been changed to debug level;
  • any errors are now propagated, make sure to catch your errors properly if you need to retain resilience.
  • since topicArn has moved to the constructor, publish(message, topicArn) is now deprecated in favour of publishRaw(message) and publishJson(message)

Amazon SQS

Updating imports

Utilities for SQS have been moved to @backpack/amazon-sqs, so make sure to install the package and update your imports.

ts
import { SqsPublisher } from '@backpack/amazon-sqs';

Changes to SqsPublisher

  • constructor injection was added, make sure to pass your own SQSClient;
  • the queueUrl method parameter has been deprecated and moved to the constructor;
  • logging has been made optional, to enable it you only need to pass your logger instance to the constructor;
  • info and error logging has been changed to debug level;
  • any errors are now propagated, make sure to catch your errors properly if you need to retain resilience.
  • since queueUrl has moved to the constructor, publish(message, queueUrl) is now deprecated in favour of sendRaw(message) and sendJson(message)

Amazon S3

Updating imports

Utilities for S3 have been moved to @backpack/amazon-s3, so make sure to install the package and update your imports.

ts
import { S3Service } from '@backpack/amazon-s3';

Changes to S3Service

  • constructor injection was added, make sure to pass your own S3Client;
  • the bucketName method parameter has been deprecated and moved to the constructor;
    • NOTE: for putObject(), instead of deprecating, we removed the old method signature entirely;
  • logging has been made optional, to enable it you only need to pass your logger instance to the constructor;
  • info and error logging has been changed to debug level;
  • deleteVersionedObject() has not been migrated (yet) due to unclear use case;
  • getObject() now accepts a type option to convert the stream to a buffer, text, arrayBuffer, blob or json;
  • getObjectStream() has been deprecated in favour of getObject(key, { type: "stream" )
  • The NoSuchKey error is still caught for deleteObject(), however, this error is not translated to the custom NotFoundException anymore.

Exception classes and error handling

For error handling, @ns/common-serverless-library provides an Exception class (including some subclasses) that represent HTTP errors.

Since Backpack advocates the RFC 9457 Problem Detail web standard, it provides the ProblemError class instead. You can use generic subclasses like NotFoundProblem to throw a similar generic error, representing a HTTP 404:

ts
import { NotFoundProblem } from "@backpack/aws-lambda/rest";

if (myBook === undefined) {
  throw NotFoundProblem("Could not find book 123")
}

Alternatively, you can define your own error classes by extending ProblemError:

ts
import { ProblemError, HttpStatus } from "@backpack/aws-lambda/rest";

class BookNotFoundProblem extends ProblemError {
  constructor(bookId: string) {
    super({
      title: "Book not found",
      detail: `Could not find book ${bookId}`,
      type: "/problems/book-not-found",
      status: HttpStatus.NOT_FOUND,
    });
  }
}

// ...

if (myBook === undefined) {
  throw BookNotFoundProblem("123")
}

To handle these errors properly, you can use the default defaultErrorHandler from @backpack/aws-lambda, in combination with the utilities from @backpack/error-handling:

ts
import { defaultErrorHandler } from "@backpack/aws-lambda/rest";
import { catchErrors } from "@backpack/error-handling/promises";

class MyLambda {
  @catchErrors(defaultErrorHandler())
  public async handle(): Promise<APIGatewayProxyResult> {
    // ...
  }
}

Note that if you need to retain the original response body structure, you can still do so by implementing a custom error converter.