Cloudflare Worker Router

repository·main·Indexed 42 days ago

https://github.com/tsndr/cloudflare-worker-router

A lightweight, zero-dependency router for Cloudflare Workers (v3.3.3) featuring middleware support, built-in CORS helpers, and easy access to request parameters and bodies. It provides a generic Router class for TypeScript, supporting standard HTTP methods and dynamic URL parameters.

Tokens
3.7K
Snippets
12
Records
18
Agent score
53%

What's inside Cloudflare Worker Router

  1. Quickstart: Basic Router Setup with TypeScript

    main

    To use the router, import Router, initialize it with your environment, context, and request extensions, and then call router.handle within your Cloudflare Worker's fetch event listener. You can register global middleware using router.use() and define routes for various HTTP methods.

    import { Router } from '@tsndr/cloudflare-worker-router'
    
    export type Env = { ENVIRONMENT: string; SECRET_TOKEN: string }
    export type ExtReq = { userId?: number }
    export type ExtCtx = {}
    
    const router = new Router<Env, ExtCtx, ExtReq>()
    
    // Global middleware
    router.use(({ env, req }) => {
        if (req.headers.get('authorization') !== env.SECRET_TOKEN)
            return new Response(null, { status: 401 })
    })
    
    // Route with URL parameter
    router.post('/user/:id', ({ req }) => {
        const userId = req.params.id
        return Response.json({ userId }, { status: 204 })
    })
    
    export default {
        async fetch(request: Request, env: Env, ctx: ExecutionContext) {
            return router.handle(request, env, ctx)
        }
    }
    import { Router } from '@tsndr/cloudflare-worker-router'
    
    // Env Types
    export type Var<T = string> = T
    export type Secret<T = string> = T
    
    export type Env = {
        ENVIRONMENT: Var<'dev' | 'prod'>
        SECRET_TOKEN: Secret
    }
    
    // Request Extension
    export type ExtReq = {
        userId?: number
    }
    
    // Context Extension
    export type ExtCtx = {}
    
    // Initialize Router
    const router = new Router<Env, ExtCtx, ExtReq>()
    
    // Enabling build in CORS support
    router.cors()
    
    // Register global middleware
    router.use(({ env, req }) => {
        // Intercept if token doesn't match
        if (req.headers.get('authorization') !== env.SECRET_TOKEN)
            return new Response(null, { status: 401 })
    })
    
    // Simple get
    router.get('/user', () => {
        return Response.json({
            id: 1,
            name: 'John Doe'
        })
    })
    
    // Post route with url parameter
    router.post('/user/:id', ({ req }) => {
    
        const userId = req.params.id
    
        // Do stuff
    
        if (!true) {
            return Response.json({
                error: 'Error doing stuff!'
            }, { status: 400 })
        }
    
        return Response.json({ userId }, { status: 204 })
    })
    
    // Delete route using a middleware
    router.delete('/user/:id', ({ env, req }) => {
        if (req.headers.get('authorization') === env.SECRET_TOKEN)
            return new Response(null, { status: 401 })
    
    }, ({ req }) => {
    
      const userId = req.params.id
    
      // Do stuff...
    
      return Response.json({ userId })
    })
    
    // Listen Cloudflare Workers Fetch Event
    export default {
        async fetch(request: Request, env: Env, ctx: ExecutionContext) {
            return router.handle(request, env, ctx)
        }
    }
  2. Migrate from v2.x.x to v3.x.x

    main

    When upgrading from version 2 to version 3, you must update the package and refactor your handler signatures. The primary change is the removal of the res and next objects from the handler parameter list. Instead of mutating a response object, you must now return a Response object (or use Response.json()) directly from your handlers and middlewares.

    npm i -D @tsndr/cloudflare-worker-router@^3
  3. Refactor Handlers and Middlewares for v3.x.x

    main

    In v3.x.x, the handler signature has changed. Follow these steps to refactor your code:

    1. Update Parameters: Remove res and next from the destructuring pattern in your handler arguments.
    2. Replace res. mutations: Instead of setting res.status or res.body, use return new Response(body, { status }) or return Response.json(body).
    3. Remove next(): Middlewares no longer use next() to pass control. To allow the request to continue, simply return nothing (or do not return a Response). To intercept/stop the request, return a Response object.
    // Register global middleware
    router.use(({ env, req }) => {
        // Intercept if token doesn't match
        if (req.headers.get('authorization') !== env.SECRET_TOKEN) {
            return new Response(null, { status: 401 })
        }
    })
    
    // Simple get
    router.get('/user', () => {
        return Response.json({
            id: 1,
            name: 'John Doe'
        })
    })
  4. Enable Debug Mode with router.debug()

    main

    Enable or disable debug mode. When enabled, the router will return the error.stack in case of an exception instead of an empty 500 response. Debug mode is disabled by default.

    router.debug([state = true])

    KeyTypeDefault Value
    statebooleantrue
    router.debug(true)
  5. Configure CORS with router.cors()

    main

    Enables built-in CORS support. When enabled, it will overwrite other OPTIONS requests.

    router.cors([config])

    KeyTypeDefault Value
    allowOriginstring*
    allowMethodsstring*
    allowHeadersstring*
    allowCredentialsbooleanundefined
    varystringundefined
    maxAgeinteger86400
    optionsSuccessStatusinteger204
  6. The req Object structure

    main

    The req object provides access to the incoming request data:

    KeyTypeDescription
    bodyobject / stringAvailable for POST, PUT, PATCH, or DELETE. Contains the received body string or a parsed JSON object.
    headersHeadersRequest Headers Object
    methodstringHTTP request method
    paramsobjectObject containing all dynamic parameters defined in the URL string
    queryobjectObject containing all query parameters
  7. Reference Supported HTTP Methods

    main

    The router supports the following methods for defining routes:

    • router.any(url, [...handlers])
    • router.delete(url, [...handlers])
    • router.get(url, [...handlers])
    • router.head(url, [...handlers])
    • router.options(url, [...handlers])
    • router.patch(url, [...handlers])
    • router.post(url, [...handlers])
    • router.put(url, [...handlers])

    Arguments:

    • url (string): The URL starting with a /. Supports dynamic parameters prefixed with : (e.g., /user/:userId). Parameters are accessible via req.params.userId.
    • handlers (function, optional): An unlimited number of functions receiving ctx as an argument.
  8. Register global middleware with use()

    main

    Use the .use(...handlers) method to register global handlers (middleware). These handlers are executed for every request processed by the router, before any route-specific handlers. This is useful for logging, authentication, or modifying the context.

    router.use(async (ctx) => {
      console.log(`Request: ${ctx.req.method} ${ctx.req.url}`);
      // Return nothing (void) to continue to the next handler
    });
  9. Configure CORS support

    main

    Enable Cross-Origin Resource Sharing (CORS) by calling .cors(config?). When enabled, the router automatically handles OPTIONS preflight requests and injects the configured CORS headers into the final Response.

    Configuration Options (RouterCorsConfig):

    • allowOrigin (string, default: '*')
    • allowMethods (string, default: '*')
    • allowHeaders (string, default: '*')
    • allowCredentials (boolean, default: undefined)
    • vary (string, default: undefined)
    • maxAge (number, default: 86400)
    • optionsSuccessStatus (number, default: 204)
    router.cors({
      allowOrigin: 'https://example.com',
      allowMethods: 'GET, POST',
      maxAge: 3600
    });