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.
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 ofgetJsonSecret(secretId, { required: false })
(will be removed in a future version)getRequiredSecretValue()
is deprecated in favour ofgetJsonSecret()
(will be removed in a future version)batchGetSecretValue()
has been removed (barely used in existing projects).
Changes to CachedSecretManagerService
- renamed from
CachedSecretManagerService
toCachedSecretsManagerService
- added constructor injection, make sure to provide a
SecretsManagerClient
; cacheExpirySeconds
moved to options object ascacheExpiryDurationSeconds
- 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.
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
andTKey
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 todebug
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 ofputItem(key, options)
getItem(key, tableName)
was deprecated in favour offindItemById(key)
removeItem(key, tableName)
was deprecated in favour ofdeleteItemById(key)
itemExists(key, tableName)
was deprecated in favour ofitemExistsById(key)
getAllItems(tableName)
was deprecated in favour ofscanAllItems(options)
- it is now possible to add your mapping functions
writeItem()
andreadItem()
, allowing mapping and/or validation with Zod. saveItem(options)
was added to perform aSave
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 aRecord<string, unknown>
instead ofRecord<string, any>
; queryTable()
was deprecated in favour ofqueryItems(options)
, which now has an options object accepting allQueryCommandInput
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.
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
anderror
logging has been changed todebug
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 ofpublishRaw(message)
andpublishJson(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.
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
anderror
logging has been changed todebug
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 ofsendRaw(message)
andsendJson(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.
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;
- NOTE: for
- logging has been made optional, to enable it you only need to pass your logger instance to the constructor;
info
anderror
logging has been changed todebug
level;deleteVersionedObject()
has not been migrated (yet) due to unclear use case;getObject()
now accepts atype
option to convert the stream to abuffer
,text
,arrayBuffer
,blob
orjson
;getObjectStream()
has been deprecated in favour ofgetObject(key, { type: "stream" )
- The
NoSuchKey
error is still caught fordeleteObject()
, however, this error is not translated to the customNotFoundException
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:
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
:
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
:
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.