Skip to main content

Routing Methods

Keq provides a flexible routing mechanism that makes middleware apply only to specific requests. Through the .apply() chainable API, you can precisely control middleware scope.

.apply(...middlewares)​

Applies one or more middleware to specified routes, returning a chain configuration object. Use .exclude() and .forRoutes() to define matching rules.

import { request } from "keq"

request
  .apply(authMiddleware, loggingMiddleware)
  .forRoutes({ host: "api.example.com" })

Parameters:

  • middlewares - One or more middleware functions

.forRoutes(...routes)​

Specifies the routes where middleware takes effect. Multiple routes have an OR relationship (matches if any one applies).

import { request } from "keq"

request
  .apply(rateLimitMiddleware)
  .forRoutes(
    { host: "api.example.com", method: "post" },
    { host: "api.example.com", method: "put" },
  )

Parameters:

  • routes - One or more KeqRoutePattern objects or KeqRoute predicate functions

KeqRoutePattern fields:

FieldTypeDescription
hoststringMatch domain
methodstringMatch HTTP method
pathnamestringGlob (minimatch) pattern to match path

Within a single KeqRoutePattern, multiple fields have an AND relationship (all fields must match).

// host AND method AND pathname must all match
request
  .apply(middleware)
  .forRoutes({ host: "api.example.com", method: "get", pathname: "/users/**" })

.forAllRoutes()​

Applies middleware to all routes. Semantically equivalent to unconditional matching — combined with .exclude(), achieves "apply globally but exclude specific routes".

import { request } from "keq"

// Apply globally
request
  .apply(loggingMiddleware)
  .forAllRoutes()

// Apply globally but exclude health checks
request
  .apply(loggingMiddleware)
  .exclude({ pathname: "/health" }, { pathname: "/ready" })
  .forAllRoutes()

.exclude(...routes)​

Excludes specific routes. Multiple exclusion conditions have an OR relationship (skip if any one matches).

import { request } from "keq"

request
  .apply(authMiddleware)
  .exclude({ pathname: "/health" }, { pathname: "/ready" })
  .forRoutes({ host: "api.example.com" })

Parameters:

  • routes - One or more KeqRoutePattern objects or KeqRoute predicate functions

Custom KeqRoute Predicates​

In addition to KeqRoutePattern objects, you can pass custom predicate functions:

import { request } from "keq"
import type { KeqRoute } from "keq"

const hasDebugParam: KeqRoute = (ctx) => {
  return ctx.request.url.searchParams.has("debug")
}

request
  .apply(debugMiddleware)
  .forRoutes(hasDebugParam)

Chaining​

.forRoutes() and .forAllRoutes() return the request instance itself, supporting continuous chain registration of multiple routed middleware groups:

import { request } from "keq"

request
  .apply(authMiddleware)
    .forRoutes({ host: "api.example.com" })
  .apply(cacheMiddleware)
    .forRoutes({ host: "cdn.example.com" })
  .apply(loggingMiddleware)
    .exclude({ pathname: "/health" })
    .forAllRoutes()

Comprehensive Example​

import { request } from "keq"

// Add auth for API requests, excluding health checks
request
  .apply(authMiddleware)
  .exclude({ pathname: "/health" }, { pathname: "/ready" })
  .forRoutes({ host: "api.example.com" })

// Add request logging for write operations
request
  .apply(logMiddleware)
  .forRoutes(
    { host: "api.example.com", method: "post" },
    { host: "api.example.com", method: "put" },
    { host: "api.example.com", method: "delete" },
  )

// Add global rate limiting, excluding internal paths
request
  .apply(rateLimitMiddleware)
  .exclude({ pathname: "/internal/**" })
  .forAllRoutes()

Execution Order​

Routed middleware executes in the order it was registered. When a request matches multiple routes, all matching middleware executes in order:

request
  .apply(middleware1).forRoutes({ host: "api.example.com" })
  .apply(middleware2).forRoutes({ pathname: "/users/**" })
  .apply(middleware3).forRoutes({ method: "get" })

// For GET https://api.example.com/users/123
// Execution order: middleware1 -> middleware2 -> middleware3 -> built-in middleware