Guides

Routing Requests

Use routers when path params and method filters are middleware concerns, not server adapter concerns.

Create a Router

Import routes from the router subpath. A router is callable middleware, so it can be added to a chain with .use().

import { chain } from 'alien-middleware'
import { routes } from 'alien-middleware/router'

const router = routes()

router.use('/health', () => {
  return new Response('ok')
})

const app = chain().use(router)

The route handler receives the same request context shape as middleware, plus route data when a path matches.

Read Path Parameters

Route paths use pathic path syntax. Parameters are inferred from the path string.

const router = routes()

router.use('/users/:userId', context => {
  return new Response(context.params.userId)
})

In this handler, context.params.userId is typed as string.

Filter by Method

Pass a method before the path to run a handler only for that method.

router.use('GET', '/items/:id', context => {
  return new Response(`read ${context.params.id}`)
})

router.use('POST', '/items', () => {
  return new Response('created', { status: 201 })
})

Use an array for multiple methods, or '*' for an explicit any-method route.

router.use(['PUT', 'PATCH'], '/items/:id', context => {
  return new Response(`write ${context.params.id}`)
})

router.use('*', '/status', () => {
  return new Response('up')
})

Routes with no method argument also match any method.

Share Middleware with Routes

Pass a middleware chain to routes() when all handlers in that router should see the chain's context additions.

import { chain } from 'alien-middleware'
import { routes } from 'alien-middleware/router'

const auth = chain().use(() => {
  return { user: { id: 'u_123', name: 'Ada' } }
})

const privateRoutes = routes(auth)

privateRoutes.use('/profile', context => {
  return new Response(context.user.name)
})

The user property is typed inside handlers registered on privateRoutes.

Combine Routers

Routers are middleware chains, so you can compose public and private route groups into one app.

const publicRoutes = routes()
publicRoutes.use('/status', () => new Response('ok'))

const privateRoutes = routes(auth)
privateRoutes.use('/profile', context => new Response(context.user.id))

const app = chain().use(publicRoutes).use(privateRoutes)

The router returns a response when a handler returns one. If no registered route matches, the parent chain continues.

Note

Path patterns do not need to be ordered from most-specific to least-specific unless two patterns are exactly the same. The matcher chooses the most specific route that matches the request path.

The router is not a Stargate, but /users/:id still gets you through the right ring.