prosto-router v0.0.1-alpha.6
Fast and Robust URI-router for NodeJS. 
This is framework agnostic router that is extremelly fast. It's as fast as find-my-way
and even faster. It's written completely on TypeScript.
The aim of the router is to properly parse URI and find the handler in the shortest possible time. It doesn't have any problems with url-encoded tricky URIs. It will deliver all the params in the context. It parses params and wildcards in proper manner. It allows to use complex wildcards and parameters with regex. It does not call handlers but returns handlers. You must specify the type of handler functions yourself for your use case.
If you want to see a benchmark comparison with the most commonly used routers, see here.
Installation
npm install prosto-router
Usage
Basic usage
import { ProstoRouter } from 'prosto-router'
import http from 'http'
const router = new ProstoRouter()
router.on('GET', '/api/path', () => 'ok')
const server = http.createServer((req, res) => {
const found = router.lookup(req.method, req.url)
if (found) {
res.end(found.route.handlers[0]())
} else {
res.statusCode = 404
res.end('404 Not Found')
}
})
server.listen(3000, (err) => {
if (err) return console.error(err)
console.log('Server is listening 3000')
})
require
example
const { ProstoRouter } = require('prosto-router')
const http = require('http')
const router = new ProstoRouter()
Router options
const router = new ProstoRouter({
// Ignore trailing URI slash
// (by default = false)
ignoreTrailingSlash: false,
// Ignore URI case (by default = false)
ignoreCase: false,
// By default duplicate paths are enabled,
// the handlers are collected into an array
disableDuplicatePath: false,
// You can put any logger that implements
// TConsoleInterface interface
logger: ...,
// Specify which log messages to see
// (DEBUG, INFO, LOG, WARN, ERROR, NOTHING)
logLevel: EProstoLogLevel.INFO,
// enables caching of mapping of
// incoming paths to the handlers
// which increases the speed of routing
// (by default 0)
cacheLimit: 50
})
Specify Handler Type for Router
type MyHandlerType = (
req: ClientRequest,
res: ServerResponse,
ctx: TProstoLookupContext
) => string
const router = new ProstoRouter<MyHandlerType>()
router.on(
'GET',
'/api/path',
(req: ClientRequest, res: ServerResponse, ctx: TProstoLookupContext) => 'ok'
)
Overwrite Handler Type for Route
router.on<MyHandlerType>(
'GET',
'/api/path',
(req: ClientRequest, res: ServerResponse, ctx: TProstoLookupContext) => 'ok'
)
Lookup result
Lookup returns TProstoLookupResult | undefined
interface TProstoLookupResult<HandlerType> {
route: TProstoRoute<HandlerType> // the matched route itself
ctx: TProstoLookupContext // the lookup context
// (contains params that were parsed from the URI)
}
// The real interface has more props
// I highlight here the main props
interface TProstoRoute<HandlerType> {
// normallized path that was registered
path: string
// array of handlers in registration order
handlers: HandlerType[]
// the route has only one static segment
// (segment is the whole url)
isStatic: boolean
// the route has at least one parameter
// (it can have static segments as well)
isParametric: boolean
// the router has wildcard(s) and static
// segment(s) (optionally)
isWildcard: boolean
}
interface TProstoLookupContext<ParamsType = Record<string, string | string[]> {
params: ParamsType // parameters from parametric routes or wildcards
}
Lookup alias (find)
router.find
works similarly to router.lookup
Parametric routes
Parameter starts with :
.
If you want to have colon in your path without defining a parameter you must escape it with backslash like so '/api/colon\\:novar'
.
Parameters can be separated with hyphen like so '/api/:key1-:key2'
It's possible to specify RegExp for parameters '/api/time/:hours(\\d{2})h:minutes(\\d{2})m'
// simple single param
router.get('/api/vars/:key', () => 'ok')
// two params separated with hyphen
router.get('/api/vars/:key1-:key2', () => 'ok')
// two params with regex
router.get('/api/time/:hours(\\d{2})h:minutes(\\d{2})m', () => 'ok')
// two params separated with slash
router.get('/api/user/:name1/:name2, () => 'ok')
// three params with the same name (leads to an array as a value)
router.get('/api/array/:name/:name/:name, () => 'ok')
Wildcards
Widlcard is specified with asterisk '*'
It can be at the beginning of path, in the middle of the path or at the end of the path.
It's possible to have several wildcards.
It's possible to have widlcards mixed with params.
// the most common usage (will match all the URIs that
// start with `/static/`)
router.get('/static/*', () => 'ok')
// will match all the URIs that start with `/static/`
// and end with `.js`
router.get('/static/*.js', () => 'ok')
// will match all the URIs that start with `/static/`
// and have `/test/` in the middle
router.get('/static/*/test/*', () => 'ok')
Retrieving the parameters and wildcard values
router.get('/api/:key1-:key2/*/array/name/name/name', () => 'ok')
const lookupResult = router.lookup('/api/val1-val2/random/part/array/name1/name2/name3')
if (lookupResult) {
console.log(lookupResult.ctx)
// {
// params: {
// key1: 'val1',
// key2: 'val2',
// '*': 'random/part',
// name: ['name1', 'name2', 'name3']
// }
// }
}
Register routes via method shortcut (get, put, post, patch, delete, options, head)
router.on('GET', '/api/path', () => 'ok')
// is equal to
router.get('/api/path', () => 'ok')
router.on('POST', '/api/path', () => 'ok')
// is equal to
router.post('/api/path', () => 'ok')
// and so on
router.post('/api/path', () => 'ok')
router.put('/api/path', () => 'ok')
router.patch('/api/path', () => 'ok')
router.delete('/api/path', () => 'ok')
router.options('/api/path', () => 'ok')
router.head('/api/path', () => 'ok')
Register Route for all methods
router.on('*', '/api/path', () => 'ok')
// is equal to
router.all('/api/path', () => 'ok')
Path builders
When you define a new route you receive a path builder for it
const pathBuilder = router.get('/api/path', () => 'ok')
console.log(pathBuilder())
// /api/path
const userPathBuilder = router.get('/api/user/:name', () => 'ok')
console.log(userPathBuilder({
name: 'John'
}))
// /api/user/John
const wildcardBuilder = router.get('/static/*', () => 'ok')
console.log(wildcardBuilder({
'*': 'index.html'
}))
// /static/index.html
const multiParamsBuilder = router.get('/api/asset/:type/:type/:id', () => 'ok')
console.log(userPathBuilder({
type: ['CJ', 'REV'],
id: '443551'
}))
// /api/asset/CJ/REV/443551
// typescript example
type MyHandlerType = () => string
interface MyParamsType = {
name: string
}
const userPathBuilder = router.get<MyHandlerType, MyParamsType>('/api/user/:name', () => 'ok')
console.log(userPathBuilder({
name: 'John'
}))
// /api/user/John
To be continued...
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago