@drupe/phylum v1.3.1
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
- Phylum / Router + app/router.use(..) + app/router.METHOD(..) + app/router.rewrite(..) + app/router.deviate(..) + app/router.router(..) + router.handler(..)
- Routes + Route Parameters
- Route Options + rewrite + method + cleanRestPath + cleanParams
- Rest Path
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, 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, 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 (withoutmethod
option).
app/router.rewrite(path, 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, 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'srestPath
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'sparams
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']
})