Skip to content

Latest commit

 

History

485 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Lambda Toolkit Logo

Lambda Toolkit

Lambda Toolkit is an open-source collection of utility functions designed to help teams write production-ready application code, for deployment to AWS Lambda, faster.

Read more in the docs here: Lambda Toolkit Docs

Features

  • Core Utilities: Logging, date utilities, schema validation, metrics, and tracing
  • Lambda HTTP Handler: Complete wrapper with observability and error handling
  • DNS Utilities: Domain name generation for consistent subdomain creation
  • DynamoDB Utilities: Helper functions for cleaning internal keys from items
  • Config Manager: Type-safe environment variable handling with validation
  • Error Classes: Built-in error classes for consistent HTTP error responses

Installation

npm install @leighton-digital/lambda-toolkit

Usage

Importing the Package

All utilities are available from the main package import:

import {
  // Core utilities
  logger,
  tracer,
  metrics,
  getISOString,
  validateSchema,

  // Lambda utilities
  withHttpHandler,

  // DNS utilities
  generateApiSubDomain,
  generateWebSubDomain,
  generateAuthDomain,
  generateCognitoDomain,
  sanitiseDnsString,

  // DynamoDB utilities
  stripInternalKeys,

  // Config manager
  envVar,

  // Error classes
  ValidationError,
  ResourceNotFoundError,
  UnauthorisedError,
  ForbiddenError,
  ConflictError,
  TooManyRequestsError
} from '@leighton-digital/lambda-toolkit';

Sub-path entrypoints

For CDK stacks, infra tests, and other code that only needs shared enums and types (for example Stage, Region, EventMessage, ResourceNameParts, Tags), import from @leighton-digital/lambda-toolkit/types. That entrypoint does not load @middy/* or Powertools middleware, so you avoid having to mock them when the root package import is not needed.

The root import still loads the full surface (including withHttpHandler); use /types when you only need types from src/types/.

Basic HTTP Handler Example

Here's a complete example showing how to use the HTTP handler with validation and error handling:

import {
  withHttpHandler,
  validateSchema,
  ValidationError,
  ResourceNotFoundError,
  logger
} from '@leighton-digital/lambda-toolkit';
import { z } from 'zod';

// Define request schema
const createUserSchema = z.object({
  name: z.string().min(1).max(100),
  email: z.string().email(),
  age: z.number().int().min(18).max(120),
});

export const handler = withHttpHandler(async ({ event }) => {
  const { userId } = event.pathParameters || {};

  if (event.httpMethod === 'POST') {
    // Create user
    const body = JSON.parse(event.body || '{}');
    const validatedUser = validateSchema(createUserSchema, body);

    logger.info('Creating user', { email: validatedUser.email });

    // Your business logic here...
    const newUser = { id: 'user123', ...validatedUser };

    return {
      statusCode: 201,
      body: { message: 'User created successfully', user: newUser },
    };
  }

  if (event.httpMethod === 'GET' && userId) {
    // Get user
    logger.info('Fetching user', { userId });

    // Your business logic here...
    const user = await getUserById(userId);
    if (!user) {
      throw new ResourceNotFoundError(`User ${userId} not found`);
    }

    return {
      statusCode: 200,
      body: { user },
    };
  }

  throw new ValidationError('Invalid request method or missing parameters');
});

async function getUserById(id: string) {
  // Mock implementation
  return id === 'user123' ? { id, name: 'Alice', email: 'alice@example.com' } : null;
}

Config Manager Example

Use the config manager for type-safe environment variable handling:

import { envVar, withHttpHandler, logger } from '@leighton-digital/lambda-toolkit';

// Validate configuration at module load time
const config = {
  apiUrl: envVar.getString('API_URL'),
  enableDebug: envVar.getBoolean('ENABLE_DEBUG'),
  maxRetries: envVar.getNumber('MAX_RETRIES'),
  timeout: envVar.getNumber('TIMEOUT_MS'),
};

export const handler = withHttpHandler(async ({ event }) => {
  logger.info('Handler configuration', {
    apiUrl: config.apiUrl,
    enableDebug: config.enableDebug,
    maxRetries: config.maxRetries,
    timeout: config.timeout,
  });

  // Your business logic here...

  return {
    statusCode: 200,
    body: { message: 'Configuration loaded successfully', config },
  };
});

DNS Utilities Example

Generate consistent domain names for different environments:

import {
  generateApiSubDomain,
  generateWebSubDomain,
  generateAuthDomain,
  generateCognitoDomain
} from '@leighton-digital/lambda-toolkit';

const stage = 'develop';
const domainName = 'example.com';

// API subdomain
const apiDomain = generateApiSubDomain({ stageName: stage, domainName });
// Returns: 'api-develop.example.com' (or 'api.example.com' for prod)

// Web subdomain
const webDomain = generateWebSubDomain({ stageName: stage, domainName });
// Returns: { stage: 'develop', subDomain: 'develop.example.com' }

// Auth domain
const authDomain = generateAuthDomain({ stageName: stage, domainName });
// Returns: { stage: 'develop', authDomain: 'auth-develop.example.com' }

// Cognito domain
const cognitoDomain = generateCognitoDomain({
  stageName: stage,
  domainName,
  serviceName: 'myapp'
});
// Returns: 'https://myapp-develop.auth.us-east-1.amazoncognito.com'

DynamoDB Utilities Example

Clean internal keys from DynamoDB items before returning them:

import { stripInternalKeys, withHttpHandler } from '@leighton-digital/lambda-toolkit';

export const handler = withHttpHandler(async ({ event }) => {
  // Mock DynamoDB item with internal keys
  const dynamoItem = {
    pk: 'USER#123',
    sk: 'PROFILE',
    gsi1pk: 'EMAIL#alice@example.com',
    gsi1sk: 'USER#123',
    name: 'Alice Johnson',
    email: 'alice@example.com',
    age: 30,
    createdAt: '2025-01-01T00:00:00.000Z',
  };

  // Strip internal DynamoDB keys
  const cleanItem = stripInternalKeys(dynamoItem);
  // Result: { name: 'Alice Johnson', email: 'alice@example.com', age: 30, createdAt: '...' }

  return {
    statusCode: 200,
    body: { user: cleanItem },
  };
});

Running Tests

To run the tests:

pnpm test

Development

To build the package:

pnpm build

To run linting:

pnpm lint

To format code:

pnpm format

Dependencies

Peer Dependencies

  • @aws-lambda-powertools/logger - Structured logging
  • @aws-lambda-powertools/metrics - Custom metrics
  • @aws-lambda-powertools/tracer - Distributed tracing
  • @middy/core - AWS Lambda middleware engine
  • @middy/http-error-handler - Middleware for handling HTTP errors gracefully
  • aws-cdk-lib - AWS CDK library (for types)
  • constructs - Core CDK construct classes and interfaces
  • http-errors - Standardized HTTP error objects
  • zod - Runtime schema validation and type inference

Key Features

  • Type Safety: Full TypeScript support with strict typing
  • Observability: Built-in logging, metrics, and tracing with AWS Lambda Powertools
  • Error Handling: Standardized HTTP error responses with proper status codes
  • Validation: Comprehensive input validation with Zod schemas and helpful error messages
  • DNS Management: Consistent domain name generation across environments
  • Environment Configuration: Type-safe environment variable handling

License

MIT License - see the LICENSE file for details

Contributing

Contributions are welcome! Please feel free to submit a pull request.


About

Lambda Toolkit is a collection of utility functions designed to help teams write production-ready application code on Lambda.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages