Skip to main content
This release is 12 versions behind 0.0.16 — the latest version of @asgard/heimdall. Jump to latest

Built and signed on GitHub Actions

A modern TypeScript framework for building type-safe API endpoints with a focus on developer experience and cross-platform compatibility

This package works with Node.js, DenoIt is unknown whether this package works with Cloudflare Workers, Bun, Browsers
It is unknown whether this package works with Cloudflare Workers
This package works with Node.js
This package works with Deno
It is unknown whether this package works with Bun
It is unknown whether this package works with Browsers
JSR Score
64%
Published
a week ago (0.0.4)

@asgard/heimdall

A type-safe API endpoint framework with file-based routing and multi-runtime support.

JSR Score npm License: MIT

Overview

@asgard/heimdall is a modern TypeScript framework for building type-safe API endpoints with a focus on developer experience and cross-platform compatibility. Named after Heimdall, the Norse god who guards the rainbow bridge to Asgard, this package creates a bridge between your file structure and various cloud platforms.

Features

  • 🛣️ Type-safe routing - Strong typing for paths, methods, and parameters
  • 🔍 Input validation - Built-in schema validation using Standard Schema
  • 💉 Service injection - Seamless integration with @asgard/hermod for service discovery
  • 🔄 Multi-runtime support - Works with Node.js, Deno, and Bun
  • 📂 File-based structure - Define endpoints with a clean, intuitive file organization
  • 🛡️ Security built-in - First-class support for authentication and authorization
  • ☁️ Serverless ready - First-class support for AWS Lambda and API Gateway

Installation

# Using npm
npm install @asgard/heimdall

# Using pnpm
pnpm add @asgard/heimdall

# Using yarn
yarn add @asgard/heimdall

# Using JSR
npx jsr add @asgard/heimdall

Quick Start

import { HeimdallEndpoint } from '@asgard/heimdall';
import { z } from 'zod';
import { UserService, LoggerService } from '../services';

// Define your endpoint
const getUserEndpoint = new HeimdallEndpoint({
  path: '/users/:id',
  method: 'GET',
  
  // Define parameter validation with Zod
  params: z.object({
    id: z.string()
  }),
  
  // Define response schema with Zod
  response: z.object({
    id: z.string(),
    name: z.string(),
    email: z.string().email()
  }),
  
  // Inject services from @asgard/hermod
  services: [UserService, LoggerService],
  
  // Implement the handler
  handler: async ({ params, services }) => {
    const { userService, logger } = services;
    
    logger.info(`Fetching user with id ${params.id}`);
    
    const user = await userService.findById(params.id);
    
    if (!user) {
      return {
        statusCode: 404,
        body: {
          message: `User with id ${params.id} not found`
        }
      };
    }
    
    return {
      statusCode: 200,
      body: user
    };
  }
});

// Register with your Heimdall server
server.registerEndpoint(getUserEndpoint);

Core Concepts

Endpoints

Endpoints are the building blocks of your API. Each endpoint combines:

  • A route (path + HTTP method)
  • Input validation (params, query, body)
  • Response schema
  • Service dependencies
  • Handler implementation

Service Injection

@asgard/heimdall integrates with @asgard/hermod for service discovery and dependency injection:

// Define the services you need
const endpoint = new HeimdallEndpoint({
  // ...
  services: [DatabaseService, LoggerService, AuthService],
  handler: async ({ services }) => {
    // Services are available and fully typed
    const { databaseService, loggerService, authService } = services;
    
    // Use your services
    const result = await databaseService.query('...');
    
    return {
      statusCode: 200,
      body: result
    };
  }
});

Schema Validation

@asgard/heimdall supports multiple validation libraries through StandardSchema specification:

Using Zod

import { z } from 'zod';

const createUserEndpoint = new HeimdallEndpoint({
  path: '/users',
  method: 'POST',
  
  // Use Zod for validation
  body: z.object({
    name: z.string(),
    email: z.string().email(),
    age: z.number().min(18),
    roles: z.array(z.string())
  }),
  
  // ...handler implementation
});

Using Arktype

import { type } from 'arktype';

const createUserEndpoint = new HeimdallEndpoint({
  path: '/users',
  method: 'POST',
  
  // Use Arktype for validation
  body: type({
    name: 'string',
    email: 'string:email',
    age: 'number>=18',
    roles: 'string[]'
  }),
  
  // ...handler implementation
});

@asgard/heimdall provides first-class support for AWS Lambda and API Gateway v2:

import { HeimdallEndpoint } from '@asgard/heimdall';
import { HeimdallAWSAPIGatewayV2Handler } from '@asgard/heimdall/aws';
import { type } from 'arktype';
import { UserService } from '../services';

// Define your endpoint
const getUserEndpoint = new HeimdallEndpoint({
  path: '/users/:id',
  method: 'GET',
  
  // Use Arktype for validation
  params: type({
    id: 'string'
  }),
  
  response: type({
    id: 'string',
    name: 'string',
    email: 'string:email'
  }),
  
  services: [UserService],
  handler: async ({ params, services }) => {
    const { userService } = services;
    const user = await userService.findById(params.id);
    
    if (!user) {
      return {
        statusCode: 404,
        body: { message: 'User not found' }
      };
    }
    
    return {
      statusCode: 200,
      body: user
    };
  }
});

// Create Lambda handler
const lambdaHandler = new HeimdallAWSAPIGatewayV2Handler(getUserEndpoint);

// Export the handler function for AWS Lambda
export const handler = lambdaHandler.handler;

The AWS adapter:

  • Automatically parses API Gateway event objects
  • Validates request data against your schemas
  • Injects services from your service discovery
  • Handles middleware through Middy
  • Returns properly formatted responses

API Reference

HeimdallEndpoint

The main class for defining endpoints.

new HeimdallEndpoint({
  path: string;            // The endpoint path (e.g., '/users/:id')
  method: HttpMethod;      // 'GET', 'POST', 'PUT', 'DELETE', or 'PATCH'
  body?: Schema;           // Request body validation schema
  response?: Schema;       // Response body schema
  search?: Schema;         // Query parameters schema
  params?: Schema;         // Path parameters schema
  services: Service[];     // Array of service constructors
  handler: Function;       // Handler implementation
})

Best Practices

  1. Define precise schemas - Be specific with your validation to catch errors early
  2. Register services early - Set up your service discovery at application startup
  3. Use dependency injection - Avoid direct imports in your handlers
  4. File structure matters - Organize your API endpoints logically
  5. Handle errors consistently - Use standard error responses across endpoints

License

MIT © Lebogang Mabala

Built and signed on
GitHub Actions
View transparency log

New Ticket: Report package

Please provide a reason for reporting this package. We will review your report and take appropriate action.

Please review the JSR usage policy before submitting a report.

Add Package

deno add jsr:@asgard/heimdall

Import symbol

import * as heimdall from "@asgard/heimdall";
or

Import directly with a jsr specifier

import * as heimdall from "jsr:@asgard/heimdall";

Add Package

pnpm i jsr:@asgard/heimdall
or (using pnpm 10.8 or older)
pnpm dlx jsr add @asgard/heimdall

Import symbol

import * as heimdall from "@asgard/heimdall";

Add Package

yarn add jsr:@asgard/heimdall
or (using Yarn 4.8 or older)
yarn dlx jsr add @asgard/heimdall

Import symbol

import * as heimdall from "@asgard/heimdall";

Add Package

npx jsr add @asgard/heimdall

Import symbol

import * as heimdall from "@asgard/heimdall";

Add Package

bunx jsr add @asgard/heimdall

Import symbol

import * as heimdall from "@asgard/heimdall";