Hooks
Hooks are a way to listen to specific events in the request/response lifecycle and to manipulate the request or response at certain steps during the dispatch process, or to terminate the request early.
The following router level hooks are available:
The following handler level hooks are available:
It is important to note that if a hook returns a value that does not resolve to undefined
, this value is sent as a response and the request is terminated.
Context
Hook listeners always receive an argument of type DispatchEvent. If an error occurred during the dispatch process, the argument is of type DispatchErrorEvent.
router.on('dispatchStart', (event) => {
event.request // Request object
event.response // Response object
event.params // Params collected during execution
event.path // Request path
event.method // GET, POST, ...
event.error // The error which occurred during the dispatch process.
event.dispatched // Indicate if the request has already been dispatched/send.
event.next() // Call the next handler/router
});
Async/Sync
Hook Listeners can be defined both asynchronously and synchronously. A synchronous hook listener can be defined as follows. In the example a callback call is also involved to illustrate how to proceed with the lifecycle in this case.
Sync
router.on('dispatchStart', (event) => {
cbMethod((err) => {
if(err) {
event.next(err);
return;
}
event.next();
})
})
Async
router.on('dispatchStart', async (event) => {
await asyncMethod();
})
Router
dispatchStart
This hook is triggered when the dispatch process starts. It signals the start of the router processing a request.
router.on('dispatchStart', async (event) => {
// do something
})
childMatch
This hook is called when a matching child router or handler is found based on certain criteria such as method and path.
router.on('childMatch', async (event) => {
// do something
})
childDispatchBefore
This hook is called before the dispatch process of the child router or handler is executed.
router.on('childDispatchBefore', async (event) => {
// do something
})
childDispatchAfter
This hook is called after the dispatch process of the child router or handler is executed.
Note
The hook is a bit special, because it is called even if the request is already dispatched. Therefore, the dispatched property must be checked if a response is to be given.
router.on('childDispatchAfter', async (event) => {
if(event.dispatched) {
// response can no longer be modified.
} else {
// response can be modified.
}
// do something
})
dispatchEnd
This hook is called after the dispatch process of the current router instance is terminated.
Note
The hook is a bit special, because it is called even if the request is already dispatched. Therefore, the dispatched property must be checked if a response is to be given.
router.on('dispatchEnd', async (event) => {
if(event.dispatched) {
// response can no longer be modified.
} else {
// response can be modified.
}
// do something
})
error
This hook is called when an error occurs during another hook, the dispatch process of a handler or child router. It can be used in different ways. Either the error is handled as in the following example and a response is sent.
router.on('error', ({ error, response }) => {
response.statusCode = error.statusCode;
return 'An error occured: ' + error.message;
})
The other option is to modify the error and pass it either with the next() method or by throwing the error.
throw
router.on('error', ({ error }) => {
error.statusCode = 500;
throw error;
});
next
router.on('error', ({ error, next }) => {
error.statusCode = 500;
next(error);
});
Handler
Handler hooks are somewhat special, as they must be defined differently than router level hooks. However, the context or the handler argument is the same as for the router hooks.
onBefore
router.use(coreHandler({
fn: () => 'Hello, World!',
onBefore({ next }) {
// do something
next();
}
}));
onAfter
router.use(coreHandler({
fn: () => 'Hello, World!',
onAfter({ next }) {
// do something
next();
}
}));
onError
router.use(coreHandler({
fn: () => 'Hello, World!',
onError({ error, next }) {
// do something
next();
}
}));