• Stars
    star
    1,747
  • Rank 26,653 (Top 0.6 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created over 4 years ago
  • Updated 2 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A little router.

Itty Router


v4.x Documentation @ itty.dev

npm version bundle size build status code coverage weekly downloads open issues

join us on discord repo stars follow the author


Itty is arguably the smallest (~450 bytes) feature-rich JavaScript router available, while enabling dead-simple API code.

Designed originally for Cloudflare Workers, itty can be used in browsers, service workers, edge functions, or runtimes like Node, Bun, etc.!

Features

Full Documentation

Complete API documentation is available at itty.dev/itty-router, or join our Discord channel to chat with community members for quick help!

Installation

npm install itty-router

Example

import {
  error,      // creates error responses
  json,       // creates JSON responses
  Router,     // the ~440 byte router itself
  withParams, // middleware: puts params directly on the Request
} from 'itty-router'
import { todos } from './external/todos'

// create a new Router
const router = Router()

router
  // add some middleware upstream on all routes
  .all('*', withParams)

  // GET list of todos
  .get('/todos', () => todos)

  // GET single todo, by ID
  .get(
    '/todos/:id',
    ({ id }) => todos.getById(id) || error(404, 'That todo was not found')
  )

  // 404 for everything else
  .all('*', () => error(404))

// Example: Cloudflare Worker module syntax
export default {
  fetch: (request, ...args) =>
    router
      .handle(request, ...args)
      .then(json)     // send as JSON
      .catch(error),  // catch errors
}

What's different about itty?

Itty does a few things very differently from other routers. This allows itty route code to be shorter and more intuitive than most!

1. Simpler handler/middleware flow.

In itty, you simply return (anything) to exit the flow. If any handler ever returns a thing, that's what the router.handle returns. If it doesn't, it's considered middleware, and the next handler is called.

That's it!

// not middleware: any handler that returns (anything at all)
(request) => [1, 4, 5, 1]

// middleware: simply doesn't return
const withUser = (request) => { 
  request.user = 'Halsey'
}

// a middleware that *might* return
const onlyHalsey = (request) => {
  if (request.user !== 'Halsey') {
    return error(403, 'Only Halsey is allowed to see this!')
  }
}

// uses middleware, then returns something
route.get('/secure', withUser, onlyHalsey,
  ({ user }) => `Hey, ${user} - welcome back!`
)

2. You don't have to build a response in each route handler.

We've been stuck in this pattern for over a decade. Almost every router still expects you to build and return a Response... in every single route.

We think you should be able to do that once, at the end. In most modern APIs for instance, we're serving JSON in the majority of our routes. So why handle that more than once?

router
  // we can still do it the manual way
  .get('/traditional', (request) => json([1, 2, 3]))

  // or defer to later
  .get('/easy-mode', (request) => [1, 2, 3])

// later, when handling a request
router
  .handle(request)
  .then(json) // we can turn any non-Response into valid JSON.

3. It's all Promises.

We await every handler, looking for a return value. If we get one, we break the flow and return your value. If we don't, we continue processing handlers/routes until we do. This means that every handler can either be synchronous or async - it's all the same.

When paired with the fact that we can simply return raw data and transform it later, this is AWESOME for working with async APIs, database layers, etc. We don't need to transform anything at the route, we can simply return the Promise (to data) itself!

Check this out:

import { myDatabase } from './somewhere'

router
  // assumes getItems() returns a Promise to some data
  .get('/items', () => myDatabase.getItems())

// later, when handling a request
router
  .handle(request)
  .then(json) // we can turn any non-Response into valid JSON.

4. Only one required argument. The rest is up to you.

We only require one argument in itty - a Request-like object with the following shape: { url, method } (usually a native Request). Because itty is not opinionated about Response creation, there is not "response" argument built in. Every other argument you pass to route.handle is given to each handler, in the same order.

This makes itty one of the most platform-agnostic routers, period, as it's able to match up to any platform's signature.

Here's an example using Cloudflare Worker arguments:

router
  .get('/my-route', (request, environment, context) => {
    // we can access anything here that was passed to `router.handle`.
  })

// Cloudflare gives us 3 arguments: request, environment, and context.
// Passing them to `route.handle` gives every route handler (above) access to each.  
export default {
  fetch: (request, env, ctx) => router
                                  .handle(request, env, ctx)
                                  .then(json)
                                  .catch(error)
}

Join the Discussion!

Have a question? Suggestion? Complaint? Want to send a gift basket?

Join us on Discord!

Testing and Contributing

  1. Fork repo
  2. Install dev dependencies via yarn
  3. Start test runner/dev mode yarn dev
  4. Add your code and tests if needed - do NOT remove/alter existing tests
  5. Commit files
  6. Submit PR (and fill out the template)
  7. I'll add you to the credits! :)

Special Thanks: Contributors

These folks are the real heroes, making open source the powerhouse that it is! Help out and get your name added to this list! <3

Core Concepts

  • @mvasigh - proxy hack wizard behind itty, coding partner in crime, maker of the entire doc site, etc, etc.
  • @hunterloftis - router.handle() method now accepts extra arguments and passed them to route functions
  • @SupremeTechnopriest - improved TypeScript support and documentation! :D

Code Golfing

  • @taralx - router internal code-golfing refactor for performance and character savings
  • @DrLoopFall - v4.x re-minification

Fixes & Build

  • @taralx - QOL fixes for contributing (dev dep fix and test file consistency) <3
  • @technoyes - three kind-of-a-big-deal errors fixed. Imagine the look on my face... thanks man!! :)
  • @roojay520 - TS interface fixes
  • @jahands - v4.x TS fixes

Documentation

More Repositories

1

apicache

Simple API-caching middleware for Express/Node.
JavaScript
1,190
star
2

itty-durable

Cloudflare Durable Objects + Itty Router = shorter code
JavaScript
194
star
3

treeize

Converts row data (in JSON/associative array format) to tree structure based on column naming conventions.
JavaScript
186
star
4

itty-router-extras

An assortment of delicious extras for the calorie-light itty-router.
JavaScript
79
star
5

itty-fetcher

An even simpler wrapper around native Fetch to strip boilerplate from your fetching code!
TypeScript
67
star
6

use-store

Storing cross-component UI data in React has never been easier... (uses hooks)
JavaScript
18
star
7

parcel-express-react

Barebones boilerplate for Parcel.js + ExpressJS + ReactJS
JavaScript
18
star
8

itty-time

An itty library to handle common time-related things for your API needs.
TypeScript
9
star
9

svelte-navlink-action

Minimalist Svelte action to inject .active class in route-matched links.
TypeScript
7
star
10

cloudflare-template-gpt

A dead-simple example of setting up a simple GPT bot API.
TypeScript
6
star
11

slick-array

Native Arrays, but with built-in index(es) and group support.
JavaScript
6
star
12

retheme-site

Home of Retheme.org
Svelte
5
star
13

adventofcode

Advent of Code 2021
JavaScript
4
star
14

yarn-release

For clean module/component releasing to NPM via Yarn
JavaScript
4
star
15

redux-registry

JavaScript
3
star
16

itty-durable-example

JavaScript
3
star
17

itty-router-help

Help middleware for itty-router
JavaScript
2
star
18

itty.sh

Svelte
2
star
19

sveltekit-template

Full-page responsive shell (with minimal element styles) for spawning new SK apps.
Svelte
2
star
20

cloudflare-kv-store

JavaScript
2
star
21

advent-of-code-2020

JavaScript
2
star
22

bundler-tests

TypeScript
1
star
23

itty-cors

CORS example using itty-router with Cloudflare Workers
JavaScript
1
star
24

pandemic-sandbox

JavaScript
1
star
25

supergeneric

Super-generic JS helper functions
HTML
1
star
26

fusebox-demo-app

JavaScript
1
star
27

portfolio

Kevin's totally awesome portfolio site.
Svelte
1
star
28

chrome-extension

JavaScript
1
star
29

aimees-model-y

Model Y Repo
1
star