Skip to content

Getting Started - itty-router

1. Install

bash
npm install itty-router
bash
yarn add itty-router
bash
pnpm i itty-router

2. Create a Router

We offer 3 Routers, depending on your needs. For most folks we recommend the "batteries-included" AutoRouter, which brings default error-handling, JSON-formatting, and the convenience middleware, withParams.

ts
import { AutoRouter } from 'itty-router'

const router = AutoRouter()
ts
import { Router } from 'itty-router'

const router = Router()
ts
import { IttyRouter } from 'itty-router'

const router = IttyRouter()

3. Register Routes

router[method: string](route: string, ...handlers): Router

To define routes, use the corresponding HTTP method "channel" on the router. For example, .get() listens to HTTP GET requests, .post() to POST, and so on.

ts
// assumes router instance (above)

router
  .get('/hello/:name', ({ params }) => `Hello, ${params.name}!`)
  .get('/json', () => ({ foo: 'bar' }))

Notes

  • These functions return the router itself, allowing chaining route definitions for convenience (see example).
  • The router.all() channel matches to ALL methods.
  • Route-definitions are the same across all router types.

4. Export Router

The router itself (intentionally) looks like the commonly-expected signature of:

ts
{ 
  fetch: (request: Request, ...args: any) => Response
}

As a result, in environments that expect that (e.g. Cloudflare Workers or Bun), we can simply export the router itself:

ts
// typically just...

export default router

(Optional) Handling Requests Manually

To manually fetch using any of the routers, simply pass your request and any additional arguments to .fetch() on the router. All matching handlers/middleware will receive these arguments and be given an opportunity to respond to the request.

ts
const request = new Request('https://foo.bar')

// assumes router is instantiated above
const response = await router.fetch(request)

Complete Example

The following examples create an equivalent API (using each of the 3 routers), including downstream JSON-formatting and catching errors.

In the example, Router uses stages to create Responses and handle errors, while IttyRouter achieves the same effect using the Promise chain of router.fetch() itself.

AutoRouter has this same functionality built-in already.

(examples assume web standards environment)

ts
import { AutoRouter } from 'itty-router'

const router = AutoRouter()

router
  .get('/hello/:name', ({ name }) => `Hello, ${name}!`)
  .get('/json', () => ({ foo: 'bar' }))
  .get('/throw', (a) => a.b.c) // safely throws

export default router
ts
import { Router, json, error, withParams } from 'itty-router'

const router = Router({
  before: [withParams], // upstream middleware
  catch: error,         // error handling
  finally: [json],      // downstream response formatting
})

router
  .get('/hello/:name', ({ name }) => `Hello, ${name}!`)
  .get('/json', () => ({ foo: 'bar' }))
  .get('/throw', (a) => a.b.c) // safely throws

export default router
ts
import { IttyRouter, json, error, withParams } from 'itty-router'

const router = IttyRouter()

router
  .all('*', withParams) // upstream middleware
  .get('/hello/:name', ({ name }) => `Hello, ${name}!`)
  .get('/json', () => ({ foo: 'bar' }))
  .get('/throw', (a) => a.b.c) // safely throws

export default {
  fetch: (request, ...args) => 
    router
      .fetch(request, ...args)
      .then(json)       // downstream response formatting
      .catch(error)     // error handling
}