itty-router

repository·v5.x·Indexed 24 days ago

https://github.com/kwhitley/itty-router

A tiny, zero-dependency API microrouter designed for environments where bundle size is a priority, such as Cloudflare Workers and other serverless runtimes. It features a small footprint (~450 to ~970 bytes), TypeScript support, and built-in route and query parsing. The library provides multiple implementations including IttyRouter, Router, and AutoRouter, along with utilities for CORS handling, request augmentation, and HTTP response generation.

Tokens
3.6K
Snippets
1
Records
25
Agent score
83%

What's inside itty-router

  1. Overview of itty-router features

    v5.x

    itty-router is an ultra-tiny API microrouter designed for environments where bundle size is critical, such as Cloudflare Workers.

    Key features include:

    • Extremely Small Size: Routers range from ~450 bytes to ~970 bytes (significantly smaller than Express.js).
    • TypeScript Support: Powerfully and flexibly typed for any environment.
    • Route & Query Parsing: Built-in support for route patterns and query parameters.
    • Middleware: Supports both built-in middleware and custom implementations.
    • Serverless Optimized: Designed specifically for serverless runtimes but works anywhere.
    • Flexible Returns: No assumptions about return types; you can return anything.
    • Future-proof: Supports HTTP methods not yet invented.
  2. Quickstart with itty-router using AutoRouter

    v5.x

    To get started quickly with a batteries-included router, use AutoRouter. It provides a convenient way to define routes for various HTTP methods and handles route parameters, JSON responses, and Promises automatically.

    When deploying to environments like Cloudflare Workers, you can export the router object using the spread operator ({ ...router }) to strip the proxy and export the underlying handler.

    import { AutoRouter } from 'itty-router' // ~1kB
    
    const router = AutoRouter()
    
    router
      .get('/hello/:name', ({ name }) => `Hello, ${name}!\`)
      .get('/json', () => [1,2,3])
      .get('/promises', () => Promise.resolve('foo'))
    
    export default { ...router } // strips the proxy
    
    // that's it ^-^
  3. Configure Router lifecycle hooks: before, catch, and finally

    v5.x

    The RouterType defines the core lifecycle hooks available on an itty-router instance. These hooks allow you to intercept requests, handle errors, and execute logic after a response has been processed:

    • before: An array of RequestHandler functions executed before the main route handlers. Use this for middleware tasks like authentication, logging, or body parsing.
    • catch: An ErrorHandler function used to catch and process errors (specifically StatusError types) that occur during the routing lifecycle.
    • finally: An array of ResponseHandler functions executed after the response has been sent. Use this for cleanup tasks or post-response logging.
  4. Define routes with parameters and wildcards

    v5.x

    The Router supports dynamic path segments and wildcards using specific syntax:

    • Named Parameters: Use :name to capture a segment. For example, /user/:id will capture the value in request.params.id.
    • Greedy Parameters: Use :name+ to capture everything from that point forward (e.g., /files/:path+).
    • Wildcards: Use * to match any remaining part of the path.

    When a route matches, the captured segments are attached to the request.params object.

  5. Use middleware hooks: before, catch, and finally

    v5.x

    The Router constructor accepts three lifecycle hooks to manage request processing:

    1. before: An array of handlers executed before any routes are tested. If a before handler returns a non-null value, that value is used as the response, and route matching is skipped.
    2. catch: An array of handlers executed if an error occurs during the before or route-matching phases. If a catch handler returns a non-null value, it becomes the response.
    3. finally: An array of handlers executed after the response has been determined (either from a route, a before hook, or a catch hook). This is useful for cleanup or logging. It receives the response as its first argument.
  6. Initialize a router with Router()

    v5.x

    The Router function is the primary entry point for creating a new router instance. It accepts an optional RouterOptions object. You can define a base path to prefix all routes and a routes array for pre-defined routes. It also supports before, catch, and finally hooks for middleware-like behavior.

    Key features:

    • Base Path: All routes defined on the router will be prefixed with the base string.
    • Route Definition: Routes are defined using HTTP method names (e.g., .get(), .post(), .put(), .delete(), .patch(), .options(), .head()) or .all() for any method.
    • Request Augmentation: The router automatically attaches params (extracted from the URL) and route (the matched path) to the request object.
  7. Throw HTTP error responses with StatusError

    v5.x

    The StatusError class is used to throw errors that carry an HTTP status code and an optional body. When caught by the router, these errors can be used to return structured error responses to the client.

    You can instantiate StatusError in two ways:

    1. With a status code and a string: The string becomes the error message.
    2. With a status code and an object: The object's error property becomes the error message, and all other properties are assigned directly to the error instance as additional metadata.
  8. Implement a custom ErrorFormatter

    v5.x

    The ErrorFormatter interface defines how errors are transformed into HTTP Response objects. It is a dual-purpose function type that can be called in two ways:

    1. By status code and body: (statusCode?: number, body?: ErrorBody) => Response. Use this when you want to manually trigger a response based on a specific status and a string or object body.
    2. By error object: (error: ErrorLike) => Response. Use this to catch an error and extract its properties (like status) to build a response.

    ErrorLike is an extension of the standard Error object that allows for an optional status property and additional arbitrary properties.

  9. Generate a Request object with toReq

    v5.x

    The toReq utility converts a shorthand string representation of a method and path into a standard Web API Request object. This is useful for testing router handlers without manually constructing full Request instances.

    Format:

    • METHOD /path (e.g., GET /user)
    • /path (defaults to GET)

    If no method is provided, it defaults to GET.

  10. Use AutoRouter for automatic route generation

    v5.x

    The AutoRouter function is a factory that returns a Router instance pre-configured with automatic parameter parsing and standard error handling. It is designed to simplify the creation of routers by automatically injecting withParams into the before middleware chain and setting up a default error handling and response formatting pipeline.

    Configuration Options

    When calling AutoRouter, you can provide an options object with the following properties:

    • format: A function used to format the response. Defaults to the json helper.
    • missing: A function called when no route matches the request. Defaults to returning a 404 error via the error helper.
    • before: An array of middleware functions to run before the route handlers. These are executed after the automatic withParams middleware.
    • finally: An array of functions to run after the route handler. The default pipeline executes:
      1. A check to see if a response exists; if not, it calls missing.
      2. The format function.
      3. Any additional functions provided in the finally array.
    • ...options: Any other standard Router options.
  11. Append CORS headers to responses with corsify()

    v5.x

    The corsify method returned by cors() is used to append CORS headers to an existing Response object. It automatically calculates the access-control-allow-origin based on your configuration and the request's origin.

    Note: corsify will skip adding headers if the response already contains an access-control-allow-origin header or if the response status is 101 (Switching Protocols).

  12. Handle incoming requests with fetch()

    v5.x

    The router instance provides a fetch method that follows the standard Web Fetch API signature. It accepts a RequestLike object and returns a Promise<Response | undefined>.

    When fetch is called:

    1. It parses URL query parameters and attaches them to request.query.
    2. It iterates through registered routes.
    3. If a method matches (or if the route is defined with 'ALL') and the URL pathname matches the route's regex, it attaches request.params and request.route.
    4. It executes the handlers sequentially. The first handler to return a non-null value will provide the response.