@drupe/phylum

Koa extension that enables performant scalable routing.

Stats

StarsIssuesVersionUpdatedCreatedSize
@drupe/phylum
1.3.13 years ago3 years agoMinified + gzip package size for @drupe/phylum in KB

Readme

phylum

Koa extension that enables performant scalable routing.

Requirements

This library is tested with node >= 10

Installation

npm i @drupe/phylum

Quick Start

import Phylum from '@drupe/phylum'

// app works the same as a koa application expect of additional routing:
const app = new Phylum()

// Add handlers with routes:
app.get('/', ctx => {
    ctx.body = 'Hello World!'
})

app.listen(8080)

Documentation


URI Component Encoding

Please note that request path components are routed in URI decoded form,
however values of the ctx.path property will retain the original encoding.


class Phylum

A Phylum instance is a Koa application that works as documented here.
In addition to the koa api, a phylum instance exposes all routing functions as documented below.

const Phylum = require('@drupe/phylum')

const app = new Phylum()
app.listen(8080)

class Router

A Router instance just routes requests and is not a Koa application itself.

const Koa = require('koa')
const {Router} = require('@drupe/phylum')

const router = new Router()

const app = new Koa()
app.use(router.handler())
app.listen(8080)

app/router.use([path, ][options, ]handler)

Register routed middleware or handler functions.

app.use('/foo', {rewrite: 1}, (ctx, next) => {
    // Do something.
})
  • path <route> - The route path as explained below.
  • options <object> - Route options as explained below.

app/router.METHOD([path, ][options, ]handler)

Register routed handler functions.
The handler is called only if the request method matches
the specified one and there is no unrouted rest path:

app.get('/foo', ctx => {
    ctx.body = 'Bar!';
})
  • METHOD - One of the following: get post put head delete options
  • path <route> - The route path as explained below.
  • options <object> - Route options as explained below (without method option).

app/router.rewrite([path, ][options, ]rewriter)

Register a routed handler function that executes a nested routing process with a different path.
The path to route is calculated by the synchronous rewriter function.
Inside the nested routing process, the ctx.path, ctx.restPath and ctx.params properties are changed according the the new path.

// Rewrite GET requests on '/foo' to '/bar':
app.rewrite('/foo', {method: 'GET'}, () => '/bar')

// This handler is now called if /foo or /bar is requested:
app.get('/bar', ctx => {
    ctx.path === '/bar'
    ctx.body = 'Hello World!'
})
  • path <route> - The route path to rewrite as explained below.
  • options <object> - Route options as explained below for mounting the rewrite handler function.
  • rewriter <function> - A function that is called for calculating the new path to route.
    • ctx - The context is passed with the first argument.
    • Return the new path to route. If a falsy value is returned, the rewrite route is ignored.

app/router.deviate([path, ][options, ]rewriter)

Like app/router.rewrite(..), but the ctx.path property is preserved.
The ctx.restPath and ctx.params properties are changed according to the new path as they are needed for routing the new path.

// Rewrite GET requests on '/foo' to '/bar':
app.deviate('/foo', {method: 'GET'}, () => '/bar')

// This handler is now called if /foo or /bar is requested:
app.get('bar', ctx => {
    // If /foo was requested:
    ctx.path === '/foo'
    // If /bar was requested:
    ctx.path === '/bar'

    ctx.body = 'Hello World!'
})

app/router.router(path, options)

Shorthand for creating a router and mounting it to the current router or application.

// Create a new router and mount at '/foo':
const router = app.router('/foo')

router.get('/bar', ctx => {
    ctx.body = 'Hello World!'
})
  • path <route> - The route path to rewrite as explained below.
  • options <object> - Route options as explained below.

router.handler(options)

Get a function that handles a context using the router.
Useful for embedding the router into an existing koa application or another routing library.

app.use(router.handler())
  • options <object> - An optional object with the following options:
    • cleanRestPath <any> - If truthy, the context's restPath property will be deleted before passing the context to the router and will be added again before calling the next function. This is useful for nesting the router into another routing library.
    • cleanParams <any> - If truthy, the context's params property will be deleted before passing the context to the router and will be added again before calling the next function.

Routes

Routes can be strings, regular expressions or a combination of both using array.
The following are valid routes:

'/foo/bar'
['foo', 'bar/']
['foo', /bar/]
[['/foo'], '/bar']
  • Duplicate, leading and trailing slashes are ignored.
  • Regular expressions are only matched against a single part of a path.

Route Parameters

Route parameters can be defined using named regular expression capturing groups:

app.get(['greet', /(?<name>.+)/], ctx => {
    // Parameters are exposed by the 'ctx.params' object:
    ctx.body = `Hello ${ctx.params.name}!`
})

Route Options

rewrite

If truthy, path and url will be rewritten to match the unrouted rest path.
Trailing slashes will be preserved.

app.use('/foo', {rewrite: 1}, ctx => {
    // Request paths will be rewritten:
    //  - /foo/bar  -> /bar
    //  - /foo/bar/ -> /bar/
})

method

If set, the handler is called only if the request method matches
the specified one and there is no unrouted rest path:

app.use('/foo', {method: 'get'}, ctx => {
    // The handler will only be called for the following paths:
    //  - /foo
    //  - /foo/
})

cleanRestPath

If set, the ctx.restPath property will not be visible to the handler:

app.use('/foo', {cleanRestPath: 1}, ctx => {
    // The restPath property will be invisible:
    ctx.restPath === undefined
    'restPath' in ctx === false
})

cleanParams

If set, the ctx.params property will not be visible to the handler:

app.use('/foo', {cleanParams: 1}, ctx => {
    // The params property will be invisible:
    ctx.params === undefined
    'params' in ctx === false
})

Rest Path

While routing, phylum keeps track of the rest path and stores it on the
context so routers can be nested in each other. The rest path is an array
containing unrouted path components (uri decoded):

app.use('/foo', ctx => {
    // If the request path was '/foo/bar/123'
    ctx.restPath // -> ['bar', '123']
})

If you find any bugs or have a feature request, please open an issue on github!

The npm package download data comes from npm's download counts api and package details come from npms.io.