Skip to content

@backpack/aws-lambda️ πŸ‘©β€πŸ’» ​

A package containing all sorts of utilities for writing AWS Lambda functions.

Installing ​

First, ensure you have set up Nexus as private registry needed to use Backpack.

Then, install the package using npm:

bash
npm install @backpack/aws-lambda

defineLambda() helpers ​

Helps to define correct AWS Lambda function handlers, by enabling type inference and enforcing the correct type definitions for your specific Lambda integration.

For example:

ts
import { 
defineRestLambda
} from "@backpack/aws-lambda";
export const
handler
=
defineRestLambda
(async (
event
,
context
) => {
// ... return {
statusCode
: 200,
body
: "OK" };
// ^ should return a `APIGatewayProxyResult` });

The following helper functions are currently provided by Backpack:

Helper functionLambda integration
defineLambda()(none or irrelevant)
defineRestLambda()API Gateway (REST)
defineSnsLambda()SNS
defineSqsLambda()SQS
defineS3Lambda()S3
defineS3BatchLambda()S3 Batch

REST event utilities ​

If your AWS Lambda integrates with API Gateway for REST APIs, you can use the following utilities for your APIGatewayProxyEvent event.

parseHeaders() ​

Parses request headers. Provides type-completion, performs normalization, and includes some validation utilities.

ts
import { APIGatewayProxyResult, 
APIGatewayProxyEvent
} from "aws-lambda";
import {
z
} from "zod";
import {
defineRestLambda
,
parseHeaders
,
jsonOk
} from "@backpack/aws-lambda/rest";
const
handler
=
defineRestLambda
(async (
event
) => {
const
headers
=
parseHeaders
(
event
);
// returns an optional header by default: const
callerId
=
headers
.
get
("X-Caller-Id");
// specifying `required: true` will always return a `string`, // and throws a `RequestValidationError` if not present const
contentType
=
headers
.
get
("Content-Type", {
required
: true });
// specifying `multi: true` will return an array instead const
acceptHeaders
=
headers
.
get
("Accept", {
multi
: true });
// specifying the `validated` option, it will validate the value against a Zod schema, // and throws a `RequestValidationError` if invalid const
Locale
=
z
.
enum
(["nl", "en"]);
const
locale
=
headers
.
get
("Accept-Language", {
validated
:
Locale
});
return
jsonOk
("OK")
})

parsePathParameters() and parseQueryParameters() ​

Both helper functions improve type-safety and include some validation utilities for parsing parameters.

ts
import { APIGatewayProxyResult } from "aws-lambda";
import { 
z
} from "zod";
import {
defineRestLambda
,
parsePathParameters
,
parseQueryParameters
,
jsonOk
,
} from "@backpack/aws-lambda/rest"; const
handler
=
defineRestLambda
(async (
event
) => {
const
pathParameters
=
parsePathParameters
(
event
);
const
queryParameters
=
parseQueryParameters
(
event
);
// returns an required header by default, // and throws a `RequestValidationError` if not present const
artistId
=
pathParameters
.
get
("artistId");
// specifying `required: false` will return a `string | undefined` instead const
departmentId
=
pathParameters
.
get
("departmentId", {
required
: false });
// specifying the `validated` option, it will validate the value against a Zod schema, // and throws a `RequestValidationError` if invalid const
SortDirection
=
z
.
enum
(["asc", "desc"]);
const
sortDirection
=
queryParameters
.
get
("sort", {
validated
:
SortDirection
});
return
jsonOk
("OK")
});

parseBody() ​

Parses a request body. Supports both plain text and JSON, and provides built-in validation utilities.

ts
import { APIGatewayProxyResult } from "aws-lambda";
import { 
z
} from "zod";
import {
defineRestLambda
,
parseBody
,
jsonOk
} from "@backpack/aws-lambda/rest";
const
handler
=
defineRestLambda
(async (
event
) => {
const
body
=
parseBody
(
event
);
const
text
=
body
.
text
();
const
json
=
body
.
json
();
// you can also type-cast a JSON object (unsafe) const
unsafeJson
=
body
.
json
<
MySchema
>();
// you can also validate your JSON against a Zod schema (safe) // throws a `RequestValidationError` if invalid const
MySchema
=
z
.
object
({
foo
:
z
.
string
(),
bar
:
z
.
string
().
optional
() })
const
safeJson
=
body
.
json
({
validated
:
MySchema
});
return
jsonOk
("OK")
}); type
MySchema
= {
foo
: string;
bar
?: string;
}

parseRequest() - all of the above ​

The function parseRequest() returns an object that include all utilities mentioned above:

  • getHeader()
  • getQueryParameter()
  • getPathParameter()
  • getBody()

REST result utilities ​

If your AWS Lambda integrates with API Gateway for REST APIs, you can use the following utilities for returning an APIGatewayProxyResult object.

result() ​

This function can be used to wrap your result object, adding additional type-completion.

For example: it hints to use the HttpStatus enum from Backpack:

aws-lambda-http-status.png

it also adds type-completion for HTTP headers:

aws-lambda-http-headers.png

jsonResult() ​

Creates a result with a JSON body. Accepts any object, and converts it to JSON. It also sets the Content-Type header to application/json.

ts
import { 
defineRestLambda
,
jsonResult
,
HttpStatus
} from "@backpack/aws-lambda/rest";
export const
handler
=
defineRestLambda
(async () => {
// ... return
jsonResult
({ /* ... */ }, {
statusCode
:
HttpStatus
.
OK
});
});

jsonOk() ​

Same as jsonResult(), but with the status code set to HTTP 200 (OK).

ts
import { 
defineRestLambda
,
jsonOk
} from "@backpack/aws-lambda/rest";
export const
handler
=
defineRestLambda
(async () => {
// ... return
jsonOk
({ /* ... */ });
});

problemResult() ​

Creates an RFC-9457 compliant problem result, to return an explicitly documented error.

ts
import {
  
defineRestLambda
,
jsonOk
,
problemResult
,
RequestValidationError
,
} from "@backpack/aws-lambda/rest"; import {
AsyncResult
} from "@backpack/error-handling/async-result";
export const
handler
=
defineRestLambda
(() =>
AsyncResult
.
try
(() => {
/* ... */ }) .
map
((
it
) =>
jsonOk
(
it
))
.
recoverIfInstanceOf
(
RequestValidationError
, () =>
problemResult
({
type
: "/problems/validation-error",
title
: "Validation error",
status
: 400,
}), ) );

Error handling ​

Combining the error handling utilities from @backpack/error-handling with the default error handler from @backpack/aws-lambda/rest allows you to easily set up proper error handling for REST endpoints.

The example below demonstrates three ways to set it up:

  1. Using the @catchErrors() decorator
  2. Using AsyncResult<T>
  3. Using Promise<T>
ts
import type { APIGatewayProxyResult } from "aws-lambda";
import { 
catchErrors
,
onFailure
,
recoverIfInstanceOf
,
orElseGet
} from "@backpack/error-handling/promises";
import {
jsonOk
,
jsonResult
,
defaultErrorHandler
,
ProblemError
} from "@backpack/aws-lambda/rest";
export class
MyLambda
{
@
catchErrors
(
onFailure
(
myErrorLogger
()),
recoverIfInstanceOf
(
MyCustomError
,
myErrorConverter
()),
orElseGet
(
defaultErrorHandler
()),
) public async
handle
():
Promise
<APIGatewayProxyResult> {
await this.
someOperation
();
return
jsonOk
("Done!");
} private async
someOperation
():
Promise
<void> {
// ... } } class
MyCustomError
extends
Error
{ /* ... */ }
function
myErrorLogger
() {
return async (
error
: unknown) =>
console
.
error
(
error
);
} function
myErrorConverter
() {
return (
error
:
MyCustomError
) =>
jsonResult
(
{
message
: `My custom error ${
error
.
message
}!` },
{
statusCode
: 500 },
); }
ts
import type { APIGatewayProxyResult } from "aws-lambda";
import { 
AsyncResult
} from "@backpack/error-handling/async-result";
import {
jsonOk
,
jsonResult
,
defaultErrorHandler
,
ProblemError
} from "@backpack/aws-lambda/rest";
export class
MyLambda
{
public
handle
():
Promise
<APIGatewayProxyResult> {
return
AsyncResult
.
try
(() => this.
someOperation
())
.
map
(() =>
jsonOk
("Done!"))
.
onFailure
(
myErrorLogger
())
.
recoverIfInstanceOf
(
MyCustomError
,
myErrorConverter
())
.
orElseGet
(
defaultErrorHandler
());
} private async
someOperation
():
Promise
<void> {
// ... throw new
ProblemError
({
type
: "/problems/foo-not-found",
status
: 404,
title
: "Foo not found!",
detail
: "Foo 123 could not be found!",
}); // ... } } class
MyCustomError
extends
Error
{ /* ... */ }
function
myErrorLogger
() {
return (
error
: unknown) =>
console
.
error
(
error
);
} function
myErrorConverter
() {
return (
error
:
MyCustomError
) =>
jsonResult
(
{
message
: `My custom error ${
error
.
message
}!` },
{
statusCode
: 500 },
); }
ts
import type { APIGatewayProxyResult } from "aws-lambda";
import { 
promiseTry
,
map
,
onFailure
,
recoverIfInstanceOf
} from "@backpack/error-handling/promises";
import {
jsonOk
,
jsonResult
,
defaultErrorHandler
,
ProblemError
} from "@backpack/aws-lambda/rest";
export class
MyLambda
{
public
handle
():
Promise
<APIGatewayProxyResult> {
return
promiseTry
(() => this.
someOperation
())
.
then
(
map
(() =>
jsonOk
("Done!")))
.
catch
(
onFailure
(
myErrorLogger
()))
.
catch
(
recoverIfInstanceOf
(
MyCustomError
,
myErrorConverter
()))
.
catch
(
defaultErrorHandler
());
} private async
someOperation
():
Promise
<void> {
// ... throw new
ProblemError
({
type
: "/problems/foo-not-found",
status
: 404,
title
: "Foo not found!",
detail
: "Foo 123 could not be found!",
}); // ... } } class
MyCustomError
extends
Error
{ /* ... */ }
function
myErrorLogger
() {
return (
error
: unknown) =>
console
.
error
(
error
);
} function
myErrorConverter
() {
return (
error
:
MyCustomError
) =>
jsonResult
(
{
message
: `My custom error ${
error
.
message
}!` },
{
statusCode
: 500 },
); }

defaultErrorHandler() ​

The default error handler from Backpack. Handles ProblemError, RequestValidationError and defines a default "catch-all" result.

Problem ​

Represents the body of an RFC-9457 Problem compliant error response.

ProblemError ​

An error with a Problem associated to it, intended to be used for error responses.

BadRequestProblem ​

A generic ProblemError that represents a Bad Request (400) HTTP error.

UnauthorizedProblem ​

A generic ProblemError that represents an Unauthorized (401) HTTP error.

ForbiddenProblem ​

A generic ProblemError that represents a Forbidden (403) HTTP error.

NotFoundProblem ​

A generic ProblemError that represents a Not Found (404) HTTP error.

InternalServerErrorProblem ​

A generic ProblemError that represents an Internal Server Error (500) HTTP error.

NotImplementedProblem ​

A generic ProblemError that represents a Not Implemented (501) HTTP error.

ServiceUnavailableProblem ​

A generic ProblemError that represents a Service Unavailable (503) HTTP error.

problemErrorConverter() ​

Converts ProblemError into a result. Included in defaultErrorHandler().

requestValidationErrorConverter() ​

Converts RequestValidationError into a result. Included in defaultErrorHandler().