tiny-request-router

Fast, generic and type safe router (match method and path).

Downloads in past

Stats

StarsIssuesVersionUpdatedCreatedSize
tiny-request-router
199241.2.24 years ago5 years agoMinified + gzip package size for tiny-request-router in KB

Readme

tiny-request-router
Fast, generic and type safe router (match request method and path).

Features

  • Minimal and opinionless router, can be used in any script and environment.
  • Matches a request method (e.g. GET) and a path (e.g. /foobar) against a list of routes
  • Uses path-to-regexp, which is used by express and therefore familiar
  • Allows wildcards (e.g. /user/(.*)/age) and named parameters (e.g. /info/:username/:age)
  • Will not call your handlers automatically, as it only cares about matching
  • Battle hardened in production (Cloudflare Worker with 10M requests per day)
  • No magic, no assumptions, no fluff, type safe, tested

Route testing

Installation

yarn add tiny-request-router
# or
npm install --save tiny-request-router

Usage (JavaScript/TypeScript)

import { Router } from 'tiny-request-router'
// NodeJS: const { Router } = require('tiny-request-router')

const router = new Router()

router
  .get('/(v1|v2)/:name/:age', 'foo1')
  .get('/info/(.*)/export', 'foo2')
  .post('/upload/user', 'foo3')

const match1 = router.match('GET', '/v1/')
// => null

const match2 = router.match('GET', '/v1/bob/22')
// => { handler: 'foo1', params: { name: 'bob', age: '22' }, ... }

Make your handlers type safe (TypeScript)

import { Router, Method, Params } from 'tiny-request-router'

// Let the router know that handlers are async functions returning a Response
type Handler = (params: Params) => Promise<Response>

const router = new Router<Handler>()
router.all('*', async () => new Response('Hello'))

const match = router.match('GET' as Method, '/foobar')
if (match) {
  // Call the async function of that match
  const response = await match.handler()
  console.log(response) // => Response('Hello')
}

Example: Cloudflare Workers (JavaScript)

Use something like wrangler to bundle the router with your worker code.
import { Router } from 'tiny-request-router'

const router = new Router()
router.get('/worker', async () => new Response('Hi from worker!'))
router.get('/hello/:name', async params => new Response(`Hello ${params.name}!`))
router.post('/test', async () => new Response('Post received!'))

// Main entry point in workers
addEventListener('fetch', event => {
  const request = event.request
  const { pathname } = new URL(request.url)

  const match = router.match(request.method, pathname)
  if (match) {
    event.respondWith(match.handler(match.params))
  }
})

API

Table of Contents

- .routes
- .all(path, handler, options) - .get(path, handler, options) - .post(path, handler, options) - .put(path, handler, options) - .patch(path, handler, options) - .delete(path, handler, options) - .head(path, handler, options) - .options(path, handler, options) - .match(method, path)

Method()

Type: ("GET" \| "POST" \| "PUT" \| "PATCH" \| "DELETE" \| "HEAD" \| "OPTIONS")
Valid HTTP methods for matching.

RouteOptions()

Extends: TokensToRegexpOptions
Optional route options.
Example:
// When `true` the regexp will be case sensitive. (default: `false`)
sensitive?: boolean;

// When `true` the regexp allows an optional trailing delimiter to match. (default: `false`)
strict?: boolean;

// When `true` the regexp will match to the end of the string. (default: `true`)
end?: boolean;

// When `true` the regexp will match from the beginning of the string. (default: `true`)
start?: boolean;

// Sets the final character for non-ending optimistic matches. (default: `/`)
delimiter?: string;

// List of characters that can also be "end" characters.
endsWith?: string;

// Encode path tokens for use in the `RegExp`.
encode?: (value: string) => string;

RouteMatch()

Extends: Route<HandlerType>
The object returned when a route matches.
The handler can then be used to execute the relevant function.
Example:
{
  params: Params
  matches?: RegExpExecArray
  method: Method | MethodWildcard
  path: string
  regexp: RegExp
  options: RouteOptions
  keys: Keys
  handler: HandlerType
}

class: Router

Tiny request router. Allows overloading of handler type to be fully type safe.
Example:
import { Router, Method, Params } from 'tiny-request-router'

// Let the router know that handlers are async functions returning a Response
type Handler = (params: Params) => Promise<Response>

const router = new Router<Handler>()

.routes

List of all registered routes.

.all(path, handler, options)


Add a route that matches any method.

.get(path, handler, options)


Add a route that matches the GET method.

.post(path, handler, options)


Add a route that matches the POST method.

.put(path, handler, options)


Add a route that matches the PUT method.

.patch(path, handler, options)


Add a route that matches the PATCH method.

.delete(path, handler, options)


Add a route that matches the DELETE method.

.head(path, handler, options)


Add a route that matches the HEAD method.

.options(path, handler, options)


Add a route that matches the OPTIONS method.

.match(method, path)


Returns: (RouteMatch<HandlerType> | null)
Match the provided method and path against the list of registered routes.
Example:
router.get('/foobar', async () => new Response('Hello'))

const match = router.match('GET', '/foobar')
if (match) {
  // Call the async function of that match
  const response = await match.handler()
  console.log(response) // => Response('Hello')
}

More info

Please check out the tiny source code
or tests for more info.

License

MIT