Routing
Parameters & constraints
A path can capture parts of the URL as named parameters. You read them off the event like any other intention, and you can make them optional, greedy, or subject to a pattern, so a route only matches when the shape is right.
#Declaring and reading parameters
Prefix a segment with : to capture it. Inside the handler, read it with event.get(name), exactly as you read query or body values, so the handler never cares where the value came from.
import { Get, EventHandler } from '@stone-js/router'
import { IncomingHttpEvent } from '@stone-js/http-core'
@EventHandler('/tasks')
export class TaskController {
// Required param, constrained to digits.
@Get('/:id', { rules: { id: /\d+/ } })
show (event: IncomingHttpEvent) {
return this.tasks.find(event.get<string>('id'))
}
// Optional param with a default.
@Get('/page/:n?', { defaults: { n: '1' } })
page (event: IncomingHttpEvent) {
return this.tasks.page(Number(event.get<string>('n')))
}
// Catch-all: matches the rest of the path.
@Get('/files/:path*')
file (event: IncomingHttpEvent) {
return this.storage.read(event.get<string>('path'))
}
}import { defineEventHandler, defineRoutes } from '@stone-js/router'
export const routes = defineRoutes([
[defineEventHandler(TaskController, 'show'),
{ path: '/tasks/:id', method: 'GET', rules: { id: /\d+/ } }],
[defineEventHandler(TaskController, 'page'),
{ path: '/tasks/page/:n?', method: 'GET', defaults: { n: '1' } }],
[defineEventHandler(TaskController, 'file'),
{ path: '/tasks/files/:path*', method: 'GET' }]
])#Parameter syntax
| Pattern | Type | Description |
|---|---|---|
| :id | required | Captures exactly one segment; the route fails to match if it is absent. |
| :id? | optional | Matches with or without the segment; pair with defaults for a fallback value. |
| :path* | catch-all (zero or more) | Captures the rest of the path, slashes included. |
| :path+ | catch-all (one or more) | Like *, but requires at least one segment. |
#Constraints with rules
The rules option maps a parameter to a pattern. The route matches only when the parameter satisfies it, so /tasks/42 reaches the handler while /tasks/abc does not, and can fall through to another route.
@Get('/:id', { rules: { id: /\d+/ } }) // digits only
@Get('/:slug', { rules: { slug: '[a-z-]+' } }) // a string pattern works too