Routing
Routing is the initial step in event processing, responsible for directing the event context to the appropriate event handler. Routes can be categorized as static or parametric, with parameters parsed from parametric routes and passed to the handler.
INFO
Wooks utilizes @prostojs/router for routing, and its documentation is partially included here for easy reference. See Router Benchmarks for performance data.
The router effectively parses URIs and quickly identifies the corresponding handler.
Content
Registering Routes
Each HTTP method has a shortcut on the app instance, plus all() for matching every method and the generic on():
import { createHttpApp } from '@wooksjs/event-http'
const app = createHttpApp()
app.get('/path', () => 'ok') // also: post, put, patch, delete, head, options
app.all('/path', () => 'ok') // matches every HTTP method
app.on('GET', '/path', () => 'ok') // generic formRouter options
Router behavior is configured via the router option of createHttpApp:
const app = createHttpApp({
router: {
ignoreTrailingSlash: true, // `/path` and `/path/` match the same route
ignoreCase: true, // case-insensitive route matching
cacheLimit: 1000, // max number of parsed routes to cache
},
})Parametric routes
Parameters in routes begin with a colon (:). To include a colon in the path without defining a parameter, it must be escaped with a backslash (/api/colon\\:novar). Parameters can be separated using a hyphen (/api/:key1-:key2). Regular expressions can also be specified for parameters (/api/time/:hours(\\d{2})h:minutes(\\d{2})m).
// Simple single param
app.get('/api/vars/:key', () => 'ok')
// Two params separated with a hyphen
app.get('/api/vars/:key1-:key2', () => 'ok')
// Two params with regex
app.get('/api/time/:hours(\\d{2})h:minutes(\\d{2})m', () => 'ok')
// Two params separated with a slash
app.get('/api/user/:name1/:name2', () => 'ok')
// Three params with the same name (leads to an array as a value)
app.get('/api/array/:name/:name/:name', () => 'ok')Wildcards
Wildcards are denoted by an asterisk (*) and offer several options:
- They can be placed at the beginning, middle, or end of a path.
- Multiple wildcards can be used.
- Wildcards can be combined with parameters.
- Regular expressions can be passed to wildcards.
// The most common usage (matches all URIs that start with `/static/`)
app.get('/static/*', () => 'ok')
// Matches all URIs that start with `/static/` and end with `.js`
app.get('/static/*.js', () => 'ok')
// Matches all URIs that start with `/static/` and have `/test/` in the middle
app.get('/static/*/test/*', () => 'ok')
// Matches all URIs that start with `/static/[numbers]`
app.get('/static/*(\\d+)', () => 'ok')Optional Parameters
A parametric (wildcard) route can include optional parameters. If you wish to define optional parameters, they should appear at the end of the route. It is not permitted to have obligatory parameters after an optional parameter, and static segments should not appear after optional parameters, except when using - and / as separators between parameters.
Optional parameters may be omitted when matching a route, and the corresponding handler will still be found.
Note: A parametric route with optional parameters is treated as a wildcard during lookup, which can reduce routing performance. Please use this feature carefully.
To define a parameter (wildcard) as optional, simply add ? at the end.
// Optional parameter
app.get('/api/vars/:optionalKey?', () => 'ok')
// Optional wildcard
app.get('/api/vars/:*?', () => 'ok')
// Several optional parameters
app.get('/api/vars/:v1/:v2?/:v3?', () => 'ok')In the above example, the router allows routes with optional parameters to be defined using the ? symbol at the end of the parameter name. For instance, /api/vars/myKey and /api/vars/ are both valid routes for the first example. Similarly, the second example allows routes like /api/vars/param1/param2 and /api/vars/ to be matched. Lastly, the third example permits routes with one, two, or three parameters to be matched, with any combination of parameters being optional.
Retrieving URI params
Access route parameters with the useRouteParams composable:
function useRouteParams<
T extends Record<string, string | string[]> = Record<string, string | string[]>
>(): {
params: T
get: <K extends keyof T>(name: K) => T[K]
}import { useRouteParams } from '@wooksjs/event-http'
app.get('hello/:name', () => {
const { get } = useRouteParams()
return `Hello ${get('name')}!`
})For repeated param names, it returns an array:
app.get('hello/:name/:name', () => {
const { get } = useRouteParams()
return get('name') // Array of names
})For wildcards, the name of the param is *:
app.get('hello/*', () => {
const { get } = useRouteParams()
return get('*') // Returns everything that follows `hello/`
})Multiple wildcards are stored as an array, similar to repeated param names.
Path builders
When defining a new route, a path builder is returned. Path builders are used to construct paths based on URI params.
const { getPath: pathBuilder } = app.get('/api/path', () => 'ok')
console.log(pathBuilder()) // /api/path
const { getPath: userPathBuilder } = app.get('/api/user/:name', () => 'ok')
console.log(
userPathBuilder({
name: 'John',
})
) // /api/user/John
const { getPath: wildcardBuilder } = app.get('/static/*', () => 'ok')
console.log(
wildcardBuilder({
'*': 'index.html',
})
) // /static/index.html
const { getPath: multiParamsBuilder } = app.get('/api/asset/:type/:type/:id', () => 'ok')
console.log(
multiParamsBuilder({
type: ['CJ', 'REV'],
id: '443551',
})
) // /api/asset/CJ/REV/443551interface MyParamsType {
name: string
}
const { getPath: userPathBuilder } = app.get<string, MyParamsType>('/api/user/:name', () => 'ok')
console.log(userPathBuilder({
name: 'John'
}))
// /api/user/JohnQuery Parameters
Query Parameters or URL Search Parameters are not part of the URI path processed by the router. The router simply ignores everything after ? or #.
To access query parameters, you can use the useUrlParams composable function from @wooksjs/event-http. For more details, refer to the Query Parameters section.