You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					696 lines
				
				20 KiB
			
		
		
			
		
	
	
					696 lines
				
				20 KiB
			| 
											3 years ago
										 | <h1 align="center">Fastify</h1> | ||
|  | 
 | ||
|  | ## Hooks
 | ||
|  | 
 | ||
|  | Hooks are registered with the `fastify.addHook` method and allow you to listen | ||
|  | to specific events in the application or request/response lifecycle. You have to | ||
|  | register a hook before the event is triggered, otherwise, the event is lost. | ||
|  | 
 | ||
|  | By using hooks you can interact directly with the lifecycle of Fastify. There | ||
|  | are Request/Reply hooks and application hooks: | ||
|  | 
 | ||
|  | - [Request/Reply Hooks](#requestreply-hooks) | ||
|  |   - [onRequest](#onrequest) | ||
|  |   - [preParsing](#preparsing) | ||
|  |   - [preValidation](#prevalidation) | ||
|  |   - [preHandler](#prehandler) | ||
|  |   - [preSerialization](#preserialization) | ||
|  |   - [onError](#onerror) | ||
|  |   - [onSend](#onsend) | ||
|  |   - [onResponse](#onresponse) | ||
|  |   - [onTimeout](#ontimeout) | ||
|  |   - [Manage Errors from a hook](#manage-errors-from-a-hook) | ||
|  |   - [Respond to a request from a hook](#respond-to-a-request-from-a-hook) | ||
|  | - [Application Hooks](#application-hooks) | ||
|  |   - [onReady](#onready) | ||
|  |   - [onClose](#onclose) | ||
|  |   - [onRoute](#onroute) | ||
|  |   - [onRegister](#onregister) | ||
|  | - [Scope](#scope) | ||
|  | - [Route level hooks](#route-level-hooks) | ||
|  | - [Diagnostics Channel Hooks](#diagnostics-channel-hooks) | ||
|  | 
 | ||
|  | **Notice:** the `done` callback is not available when using `async`/`await` or | ||
|  | returning a `Promise`. If you do invoke a `done` callback in this situation | ||
|  | unexpected behavior may occur, e.g. duplicate invocation of handlers. | ||
|  | 
 | ||
|  | ## Request/Reply Hooks
 | ||
|  | 
 | ||
|  | [Request](./Request.md) and [Reply](./Reply.md) are the core Fastify objects. | ||
|  | 
 | ||
|  | `done` is the function to continue with the [lifecycle](./Lifecycle.md). | ||
|  | 
 | ||
|  | It is easy to understand where each hook is executed by looking at the | ||
|  | [lifecycle page](./Lifecycle.md). | ||
|  | 
 | ||
|  | Hooks are affected by Fastify's encapsulation, and can thus be applied to | ||
|  | selected routes. See the [Scopes](#scope) section for more information. | ||
|  | 
 | ||
|  | There are eight different hooks that you can use in Request/Reply *(in order of | ||
|  | execution)*: | ||
|  | 
 | ||
|  | ### onRequest
 | ||
|  | ```js | ||
|  | fastify.addHook('onRequest', (request, reply, done) => { | ||
|  |   // Some code | ||
|  |   done() | ||
|  | }) | ||
|  | ``` | ||
|  | Or `async/await`: | ||
|  | ```js | ||
|  | fastify.addHook('onRequest', async (request, reply) => { | ||
|  |   // Some code | ||
|  |   await asyncMethod() | ||
|  | }) | ||
|  | ``` | ||
|  | 
 | ||
|  | **Notice:** in the [onRequest](#onrequest) hook, `request.body` will always be | ||
|  | `null`, because the body parsing happens before the | ||
|  | [preValidation](#prevalidation) hook. | ||
|  | 
 | ||
|  | ### preParsing
 | ||
|  | 
 | ||
|  | If you are using the `preParsing` hook, you can transform the request payload | ||
|  | stream before it is parsed. It receives the request and reply objects as other | ||
|  | hooks, and a stream with the current request payload. | ||
|  | 
 | ||
|  | If it returns a value (via `return` or via the callback function), it must | ||
|  | return a stream. | ||
|  | 
 | ||
|  | For instance, you can uncompress the request body: | ||
|  | 
 | ||
|  | ```js | ||
|  | fastify.addHook('preParsing', (request, reply, payload, done) => { | ||
|  |   // Some code | ||
|  |   done(null, newPayload) | ||
|  | }) | ||
|  | ``` | ||
|  | Or `async/await`: | ||
|  | ```js | ||
|  | fastify.addHook('preParsing', async (request, reply, payload) => { | ||
|  |   // Some code | ||
|  |   await asyncMethod() | ||
|  |   return newPayload | ||
|  | }) | ||
|  | ``` | ||
|  | 
 | ||
|  | **Notice:** in the [preParsing](#preparsing) hook, `request.body` will always be | ||
|  | `null`, because the body parsing happens before the | ||
|  | [preValidation](#prevalidation) hook. | ||
|  | 
 | ||
|  | **Notice:** you should also add a `receivedEncodedLength` property to the | ||
|  | returned stream. This property is used to correctly match the request payload | ||
|  | with the `Content-Length` header value. Ideally, this property should be updated | ||
|  | on each received chunk. | ||
|  | 
 | ||
|  | **Notice**: The old syntaxes `function(request, reply, done)` and `async | ||
|  | function(request, reply)` for the parser are still supported but they are | ||
|  | deprecated. | ||
|  | 
 | ||
|  | ### preValidation
 | ||
|  | 
 | ||
|  | If you are using the `preValidation` hook, you can change the payload before it | ||
|  | is validated. For example: | ||
|  | 
 | ||
|  | ```js | ||
|  | fastify.addHook('preValidation', (request, reply, done) => { | ||
|  |   request.body = { ...request.body, importantKey: 'randomString' } | ||
|  |   done() | ||
|  | }) | ||
|  | ``` | ||
|  | Or `async/await`: | ||
|  | ```js | ||
|  | fastify.addHook('preValidation', async (request, reply) => { | ||
|  |   const importantKey = await generateRandomString() | ||
|  |   request.body = { ...request.body, importantKey } | ||
|  | }) | ||
|  | ``` | ||
|  | 
 | ||
|  | ### preHandler
 | ||
|  | ```js | ||
|  | fastify.addHook('preHandler', (request, reply, done) => { | ||
|  |   // some code | ||
|  |   done() | ||
|  | }) | ||
|  | ``` | ||
|  | Or `async/await`: | ||
|  | ```js | ||
|  | fastify.addHook('preHandler', async (request, reply) => { | ||
|  |   // Some code | ||
|  |   await asyncMethod() | ||
|  | }) | ||
|  | ``` | ||
|  | ### preSerialization
 | ||
|  | 
 | ||
|  | If you are using the `preSerialization` hook, you can change (or replace) the | ||
|  | payload before it is serialized. For example: | ||
|  | 
 | ||
|  | ```js | ||
|  | fastify.addHook('preSerialization', (request, reply, payload, done) => { | ||
|  |   const err = null | ||
|  |   const newPayload = { wrapped: payload } | ||
|  |   done(err, newPayload) | ||
|  | }) | ||
|  | ``` | ||
|  | Or `async/await`: | ||
|  | ```js | ||
|  | fastify.addHook('preSerialization', async (request, reply, payload) => { | ||
|  |   return { wrapped: payload } | ||
|  | }) | ||
|  | ``` | ||
|  | 
 | ||
|  | Note: the hook is NOT called if the payload is a `string`, a `Buffer`, a | ||
|  | `stream`, or `null`. | ||
|  | 
 | ||
|  | ### onError
 | ||
|  | ```js | ||
|  | fastify.addHook('onError', (request, reply, error, done) => { | ||
|  |   // Some code | ||
|  |   done() | ||
|  | }) | ||
|  | ``` | ||
|  | Or `async/await`: | ||
|  | ```js | ||
|  | fastify.addHook('onError', async (request, reply, error) => { | ||
|  |   // Useful for custom error logging | ||
|  |   // You should not use this hook to update the error | ||
|  | }) | ||
|  | ``` | ||
|  | This hook is useful if you need to do some custom error logging or add some | ||
|  | specific header in case of error. | ||
|  | 
 | ||
|  | It is not intended for changing the error, and calling `reply.send` will throw | ||
|  | an exception. | ||
|  | 
 | ||
|  | This hook will be executed only after the `customErrorHandler` has been | ||
|  | executed, and only if the `customErrorHandler` sends an error back to the user | ||
|  | *(Note that the default `customErrorHandler` always sends the error back to the | ||
|  | user)*. | ||
|  | 
 | ||
|  | **Notice:** unlike the other hooks, pass an error to the `done` function is not | ||
|  | supported. | ||
|  | 
 | ||
|  | ### onSend
 | ||
|  | If you are using the `onSend` hook, you can change the payload. For example: | ||
|  | 
 | ||
|  | ```js | ||
|  | fastify.addHook('onSend', (request, reply, payload, done) => { | ||
|  |   const err = null; | ||
|  |   const newPayload = payload.replace('some-text', 'some-new-text') | ||
|  |   done(err, newPayload) | ||
|  | }) | ||
|  | ``` | ||
|  | Or `async/await`: | ||
|  | ```js | ||
|  | fastify.addHook('onSend', async (request, reply, payload) => { | ||
|  |   const newPayload = payload.replace('some-text', 'some-new-text') | ||
|  |   return newPayload | ||
|  | }) | ||
|  | ``` | ||
|  | 
 | ||
|  | You can also clear the payload to send a response with an empty body by | ||
|  | replacing the payload with `null`: | ||
|  | 
 | ||
|  | ```js | ||
|  | fastify.addHook('onSend', (request, reply, payload, done) => { | ||
|  |   reply.code(304) | ||
|  |   const newPayload = null | ||
|  |   done(null, newPayload) | ||
|  | }) | ||
|  | ``` | ||
|  | 
 | ||
|  | > You can also send an empty body by replacing the payload with the empty string
 | ||
|  | > `''`, but be aware that this will cause the `Content-Length` header to be set
 | ||
|  | > to `0`, whereas the `Content-Length` header will not be set if the payload is
 | ||
|  | > `null`.
 | ||
|  | 
 | ||
|  | Note: If you change the payload, you may only change it to a `string`, a | ||
|  | `Buffer`, a `stream`, or `null`. | ||
|  | 
 | ||
|  | 
 | ||
|  | ### onResponse
 | ||
|  | ```js | ||
|  | fastify.addHook('onResponse', (request, reply, done) => { | ||
|  |   // Some code | ||
|  |   done() | ||
|  | }) | ||
|  | ``` | ||
|  | Or `async/await`: | ||
|  | ```js | ||
|  | fastify.addHook('onResponse', async (request, reply) => { | ||
|  |   // Some code | ||
|  |   await asyncMethod() | ||
|  | }) | ||
|  | ``` | ||
|  | 
 | ||
|  | The `onResponse` hook is executed when a response has been sent, so you will not | ||
|  | be able to send more data to the client. It can however be useful for sending | ||
|  | data to external services, for example, to gather statistics. | ||
|  | 
 | ||
|  | ### onTimeout
 | ||
|  | 
 | ||
|  | ```js | ||
|  | fastify.addHook('onTimeout', (request, reply, done) => { | ||
|  |   // Some code | ||
|  |   done() | ||
|  | }) | ||
|  | ``` | ||
|  | Or `async/await`: | ||
|  | ```js | ||
|  | fastify.addHook('onTimeout', async (request, reply) => { | ||
|  |   // Some code | ||
|  |   await asyncMethod() | ||
|  | }) | ||
|  | ``` | ||
|  | `onTimeout` is useful if you need to monitor the request timed out in your | ||
|  | service (if the `connectionTimeout` property is set on the Fastify instance). | ||
|  | The `onTimeout` hook is executed when a request is timed out and the HTTP socket | ||
|  | has been hanged up. Therefore, you will not be able to send data to the client. | ||
|  | 
 | ||
|  | 
 | ||
|  | ### Manage Errors from a hook
 | ||
|  | If you get an error during the execution of your hook, just pass it to `done()` | ||
|  | and Fastify will automatically close the request and send the appropriate error | ||
|  | code to the user. | ||
|  | 
 | ||
|  | ```js | ||
|  | fastify.addHook('onRequest', (request, reply, done) => { | ||
|  |   done(new Error('Some error')) | ||
|  | }) | ||
|  | ``` | ||
|  | 
 | ||
|  | If you want to pass a custom error code to the user, just use `reply.code()`: | ||
|  | ```js | ||
|  | fastify.addHook('preHandler', (request, reply, done) => { | ||
|  |   reply.code(400) | ||
|  |   done(new Error('Some error')) | ||
|  | }) | ||
|  | ``` | ||
|  | *The error will be handled by [`Reply`](./Reply.md#errors).* | ||
|  | 
 | ||
|  | Or if you're using `async/await` you can just throw an error: | ||
|  | ```js | ||
|  | fastify.addHook('onResponse', async (request, reply) => { | ||
|  |   throw new Error('Some error') | ||
|  | }) | ||
|  | ``` | ||
|  | 
 | ||
|  | ### Respond to a request from a hook
 | ||
|  | 
 | ||
|  | If needed, you can respond to a request before you reach the route handler, for | ||
|  | example when implementing an authentication hook. Replying from a hook implies | ||
|  | that the hook chain is __stopped__ and the rest of the hooks and handlers are | ||
|  | not executed. If the hook is using the callback approach, i.e. it is not an | ||
|  | `async` function or it returns a `Promise`, it is as simple as calling | ||
|  | `reply.send()` and avoiding calling the callback. If the hook is `async`, | ||
|  | `reply.send()` __must__ be called _before_ the function returns or the promise | ||
|  | resolves, otherwise, the request will proceed. When `reply.send()` is called | ||
|  | outside of the promise chain, it is important to `return reply` otherwise the | ||
|  | request will be executed twice. | ||
|  | 
 | ||
|  | It is important to __not mix callbacks and `async`/`Promise`__, otherwise the | ||
|  | hook chain will be executed twice. | ||
|  | 
 | ||
|  | If you are using `onRequest` or `preHandler` use `reply.send`. | ||
|  | 
 | ||
|  | ```js | ||
|  | fastify.addHook('onRequest', (request, reply, done) => { | ||
|  |   reply.send('Early response') | ||
|  | }) | ||
|  | 
 | ||
|  | // Works with async functions too | ||
|  | fastify.addHook('preHandler', async (request, reply) => { | ||
|  |   await something() | ||
|  |   reply.send({ hello: 'world' }) | ||
|  |   return reply // optional in this case, but it is a good practice | ||
|  | }) | ||
|  | ``` | ||
|  | 
 | ||
|  | If you want to respond with a stream, you should avoid using an `async` function | ||
|  | for the hook. If you must use an `async` function, your code will need to follow | ||
|  | the pattern in | ||
|  | [test/hooks-async.js](https://github.com/fastify/fastify/blob/94ea67ef2d8dce8a955d510cd9081aabd036fa85/test/hooks-async.js#L269-L275). | ||
|  | 
 | ||
|  | ```js | ||
|  | fastify.addHook('onRequest', (request, reply, done) => { | ||
|  |   const stream = fs.createReadStream('some-file', 'utf8') | ||
|  |   reply.send(stream) | ||
|  | }) | ||
|  | ``` | ||
|  | 
 | ||
|  | If you are sending a response without `await` on it, make sure to always `return | ||
|  | reply`: | ||
|  | 
 | ||
|  | ```js | ||
|  | fastify.addHook('preHandler', async (request, reply) => { | ||
|  |   setImmediate(() => { reply.send('hello') }) | ||
|  | 
 | ||
|  |   // This is needed to signal the handler to wait for a response | ||
|  |   // to be sent outside of the promise chain | ||
|  |   return reply | ||
|  | }) | ||
|  | 
 | ||
|  | fastify.addHook('preHandler', async (request, reply) => { | ||
|  |   // the @fastify/static plugin will send a file asynchronously, | ||
|  |   // so we should return reply | ||
|  |   reply.sendFile('myfile') | ||
|  |   return reply | ||
|  | }) | ||
|  | ``` | ||
|  | 
 | ||
|  | ## Application Hooks
 | ||
|  | 
 | ||
|  | You can hook into the application-lifecycle as well. | ||
|  | 
 | ||
|  | - [onReady](#onready) | ||
|  | - [onClose](#onclose) | ||
|  | - [onRoute](#onroute) | ||
|  | - [onRegister](#onregister) | ||
|  | 
 | ||
|  | ### onReady
 | ||
|  | Triggered before the server starts listening for requests and when `.ready()` is | ||
|  | invoked. It cannot change the routes or add new hooks. Registered hook functions | ||
|  | are executed serially. Only after all `onReady` hook functions have completed | ||
|  | will the server start listening for requests. Hook functions accept one | ||
|  | argument: a callback, `done`, to be invoked after the hook function is complete. | ||
|  | Hook functions are invoked with `this` bound to the associated Fastify instance. | ||
|  | 
 | ||
|  | ```js | ||
|  | // callback style | ||
|  | fastify.addHook('onReady', function (done) { | ||
|  |   // Some code | ||
|  |   const err = null; | ||
|  |   done(err) | ||
|  | }) | ||
|  | 
 | ||
|  | // or async/await style | ||
|  | fastify.addHook('onReady', async function () { | ||
|  |   // Some async code | ||
|  |   await loadCacheFromDatabase() | ||
|  | }) | ||
|  | ``` | ||
|  | 
 | ||
|  | ### onClose
 | ||
|  | <a id="on-close"></a> | ||
|  | 
 | ||
|  | Triggered when `fastify.close()` is invoked to stop the server. It is useful | ||
|  | when [plugins](./Plugins.md) need a "shutdown" event, for example, to close an | ||
|  | open connection to a database. | ||
|  | 
 | ||
|  | The hook function takes the Fastify instance as a first argument,  | ||
|  | and a `done` callback for synchronous hook functions. | ||
|  | ```js | ||
|  | // callback style | ||
|  | fastify.addHook('onClose', (instance, done) => { | ||
|  |   // Some code | ||
|  |   done() | ||
|  | }) | ||
|  | 
 | ||
|  | // or async/await style | ||
|  | fastify.addHook('onClose', async (instance) => { | ||
|  |   // Some async code | ||
|  |   await closeDatabaseConnections() | ||
|  | }) | ||
|  | ``` | ||
|  | 
 | ||
|  | ### onRoute
 | ||
|  | <a id="on-route"></a> | ||
|  | 
 | ||
|  | Triggered when a new route is registered. Listeners are passed a `routeOptions` | ||
|  | object as the sole parameter. The interface is synchronous, and, as such, the | ||
|  | listeners are not passed a callback. This hook is encapsulated. | ||
|  | ```js | ||
|  | fastify.addHook('onRoute', (routeOptions) => { | ||
|  |   //Some code | ||
|  |   routeOptions.method | ||
|  |   routeOptions.schema | ||
|  |   routeOptions.url // the complete URL of the route, it will include the prefix if any | ||
|  |   routeOptions.path // `url` alias | ||
|  |   routeOptions.routePath // the URL of the route without the prefix | ||
|  |   routeOptions.bodyLimit | ||
|  |   routeOptions.logLevel | ||
|  |   routeOptions.logSerializers | ||
|  |   routeOptions.prefix | ||
|  | }) | ||
|  | ``` | ||
|  | 
 | ||
|  | If you are authoring a plugin and you need to customize application routes, like | ||
|  | modifying the options or adding new route hooks, this is the right place. | ||
|  | 
 | ||
|  | ```js | ||
|  | fastify.addHook('onRoute', (routeOptions) => { | ||
|  |   function onPreSerialization(request, reply, payload, done) { | ||
|  |     // Your code | ||
|  |     done(null, payload) | ||
|  |   } | ||
|  |   // preSerialization can be an array or undefined | ||
|  |   routeOptions.preSerialization = [...(routeOptions.preSerialization || []), onPreSerialization] | ||
|  | }) | ||
|  | ``` | ||
|  | 
 | ||
|  | ### onRegister
 | ||
|  | <a id="on-register"></a> | ||
|  | 
 | ||
|  | Triggered when a new plugin is registered and a new encapsulation context is | ||
|  | created. The hook will be executed **before** the registered code. | ||
|  | 
 | ||
|  | This hook can be useful if you are developing a plugin that needs to know when a | ||
|  | plugin context is formed, and you want to operate in that specific context, thus | ||
|  | this hook is encapsulated. | ||
|  | 
 | ||
|  | **Note:** This hook will not be called if a plugin is wrapped inside | ||
|  | [`fastify-plugin`](https://github.com/fastify/fastify-plugin). | ||
|  | ```js | ||
|  | fastify.decorate('data', []) | ||
|  | 
 | ||
|  | fastify.register(async (instance, opts) => { | ||
|  |   instance.data.push('hello') | ||
|  |   console.log(instance.data) // ['hello'] | ||
|  | 
 | ||
|  |   instance.register(async (instance, opts) => { | ||
|  |     instance.data.push('world') | ||
|  |     console.log(instance.data) // ['hello', 'world'] | ||
|  |   }, { prefix: '/hola' }) | ||
|  | }, { prefix: '/ciao' }) | ||
|  | 
 | ||
|  | fastify.register(async (instance, opts) => { | ||
|  |   console.log(instance.data) // [] | ||
|  | }, { prefix: '/hello' }) | ||
|  | 
 | ||
|  | fastify.addHook('onRegister', (instance, opts) => { | ||
|  |   // Create a new array from the old one | ||
|  |   // but without keeping the reference | ||
|  |   // allowing the user to have encapsulated | ||
|  |   // instances of the `data` property | ||
|  |   instance.data = instance.data.slice() | ||
|  | 
 | ||
|  |   // the options of the new registered instance | ||
|  |   console.log(opts.prefix) | ||
|  | }) | ||
|  | ``` | ||
|  | 
 | ||
|  | ## Scope
 | ||
|  | <a id="scope"></a> | ||
|  | 
 | ||
|  | Except for [onClose](#onclose), all hooks are encapsulated. This means that you | ||
|  | can decide where your hooks should run by using `register` as explained in the | ||
|  | [plugins guide](../Guides/Plugins-Guide.md). If you pass a function, that | ||
|  | function is bound to the right Fastify context and from there you have full | ||
|  | access to the Fastify API. | ||
|  | 
 | ||
|  | ```js | ||
|  | fastify.addHook('onRequest', function (request, reply, done) { | ||
|  |   const self = this // Fastify context | ||
|  |   done() | ||
|  | }) | ||
|  | ``` | ||
|  | 
 | ||
|  | Note that the Fastify context in each hook is the same as the plugin where the | ||
|  | route was registered, for example: | ||
|  | 
 | ||
|  | ```js | ||
|  | fastify.addHook('onRequest', async function (req, reply) { | ||
|  |   if (req.raw.url === '/nested') { | ||
|  |     assert.strictEqual(this.foo, 'bar') | ||
|  |   } else { | ||
|  |     assert.strictEqual(this.foo, undefined) | ||
|  |   } | ||
|  | }) | ||
|  | 
 | ||
|  | fastify.get('/', async function (req, reply) { | ||
|  |   assert.strictEqual(this.foo, undefined) | ||
|  |   return { hello: 'world' } | ||
|  | }) | ||
|  | 
 | ||
|  | fastify.register(async function plugin (fastify, opts) { | ||
|  |   fastify.decorate('foo', 'bar') | ||
|  | 
 | ||
|  |   fastify.get('/nested', async function (req, reply) { | ||
|  |     assert.strictEqual(this.foo, 'bar') | ||
|  |     return { hello: 'world' } | ||
|  |   }) | ||
|  | }) | ||
|  | ``` | ||
|  | 
 | ||
|  | Warn: if you declare the function with an [arrow | ||
|  | function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions), | ||
|  | the `this` will not be Fastify, but the one of the current scope. | ||
|  | 
 | ||
|  | 
 | ||
|  | ## Route level hooks
 | ||
|  | <a id="route-hooks"></a> | ||
|  | 
 | ||
|  | You can declare one or more custom lifecycle hooks ([onRequest](#onrequest), | ||
|  | [onResponse](#onresponse), [preParsing](#preparsing), | ||
|  | [preValidation](#prevalidation), [preHandler](#prehandler), | ||
|  | [preSerialization](#preserialization), [onSend](#onsend), | ||
|  | [onTimeout](#ontimeout), and [onError](#onerror)) hook(s) that will be | ||
|  | **unique** for the route. If you do so, those hooks are always executed as the | ||
|  | last hook in their category. | ||
|  | 
 | ||
|  | This can be useful if you need to implement authentication, where the | ||
|  | [preParsing](#preparsing) or [preValidation](#prevalidation) hooks are exactly | ||
|  | what you need. Multiple route-level hooks can also be specified as an array. | ||
|  | 
 | ||
|  | ```js | ||
|  | fastify.addHook('onRequest', (request, reply, done) => { | ||
|  |   // Your code | ||
|  |   done() | ||
|  | }) | ||
|  | 
 | ||
|  | fastify.addHook('onResponse', (request, reply, done) => { | ||
|  |   // your code | ||
|  |   done() | ||
|  | }) | ||
|  | 
 | ||
|  | fastify.addHook('preParsing', (request, reply, done) => { | ||
|  |   // Your code | ||
|  |   done() | ||
|  | }) | ||
|  | 
 | ||
|  | fastify.addHook('preValidation', (request, reply, done) => { | ||
|  |   // Your code | ||
|  |   done() | ||
|  | }) | ||
|  | 
 | ||
|  | fastify.addHook('preHandler', (request, reply, done) => { | ||
|  |   // Your code | ||
|  |   done() | ||
|  | }) | ||
|  | 
 | ||
|  | fastify.addHook('preSerialization', (request, reply, payload, done) => { | ||
|  |   // Your code | ||
|  |   done(null, payload) | ||
|  | }) | ||
|  | 
 | ||
|  | fastify.addHook('onSend', (request, reply, payload, done) => { | ||
|  |   // Your code | ||
|  |   done(null, payload) | ||
|  | }) | ||
|  | 
 | ||
|  | fastify.addHook('onTimeout', (request, reply, done) => { | ||
|  |   // Your code | ||
|  |   done() | ||
|  | }) | ||
|  | 
 | ||
|  | fastify.addHook('onError', (request, reply, error, done) => { | ||
|  |   // Your code | ||
|  |   done() | ||
|  | }) | ||
|  | 
 | ||
|  | fastify.route({ | ||
|  |   method: 'GET', | ||
|  |   url: '/', | ||
|  |   schema: { ... }, | ||
|  |   onRequest: function (request, reply, done) { | ||
|  |     // This hook will always be executed after the shared `onRequest` hooks | ||
|  |     done() | ||
|  |   }, | ||
|  |   onResponse: function (request, reply, done) { | ||
|  |     // this hook will always be executed after the shared `onResponse` hooks | ||
|  |     done() | ||
|  |   }, | ||
|  |   preParsing: function (request, reply, done) { | ||
|  |     // This hook will always be executed after the shared `preParsing` hooks | ||
|  |     done() | ||
|  |   }, | ||
|  |   preValidation: function (request, reply, done) { | ||
|  |     // This hook will always be executed after the shared `preValidation` hooks | ||
|  |     done() | ||
|  |   }, | ||
|  |   preHandler: function (request, reply, done) { | ||
|  |     // This hook will always be executed after the shared `preHandler` hooks | ||
|  |     done() | ||
|  |   }, | ||
|  |   // // Example with an array. All hooks support this syntax. | ||
|  |   // | ||
|  |   // preHandler: [function (request, reply, done) { | ||
|  |   //   // This hook will always be executed after the shared `preHandler` hooks | ||
|  |   //   done() | ||
|  |   // }], | ||
|  |   preSerialization: (request, reply, payload, done) => { | ||
|  |     // This hook will always be executed after the shared `preSerialization` hooks | ||
|  |     done(null, payload) | ||
|  |   }, | ||
|  |   onSend: (request, reply, payload, done) => { | ||
|  |     // This hook will always be executed after the shared `onSend` hooks | ||
|  |     done(null, payload) | ||
|  |   }, | ||
|  |   onTimeout: (request, reply, done) => { | ||
|  |     // This hook will always be executed after the shared `onTimeout` hooks | ||
|  |     done() | ||
|  |   }, | ||
|  |   onError: (request, reply, error, done) => { | ||
|  |     // This hook will always be executed after the shared `onError` hooks | ||
|  |     done() | ||
|  |   }, | ||
|  |   handler: function (request, reply) { | ||
|  |     reply.send({ hello: 'world' }) | ||
|  |   } | ||
|  | }) | ||
|  | ``` | ||
|  | 
 | ||
|  | **Note**: both options also accept an array of functions. | ||
|  | 
 | ||
|  | ## Diagnostics Channel Hooks
 | ||
|  | 
 | ||
|  | > **Note:** The `diagnostics_channel` is currently experimental on Node.js, so
 | ||
|  | > its API is subject to change even in semver-patch releases of Node.js. For
 | ||
|  | > versions of Node.js supported by Fastify where `diagnostics_channel` is
 | ||
|  | > unavailable, the hook will use the
 | ||
|  | > [polyfill](https://www.npmjs.com/package/diagnostics_channel) if it is
 | ||
|  | > available. Otherwise this feature will not be present.
 | ||
|  | 
 | ||
|  | Currently, one | ||
|  | [`diagnostics_channel`](https://nodejs.org/api/diagnostics_channel.html) publish | ||
|  | event, `'fastify.initialization'`, happens at initialization time. The Fastify | ||
|  | instance is passed into the hook as a property of the object passed in. At this | ||
|  | point, the instance can be interacted with to add hooks, plugins, routes or any | ||
|  | other sort of modification. | ||
|  | 
 | ||
|  | For example, a tracing package might do something like the following (which is, | ||
|  | of course, a simplification). This would be in a file loaded in the | ||
|  | initialization of the tracking package, in the typical "require instrumentation | ||
|  | tools first" fashion. | ||
|  | 
 | ||
|  | ```js | ||
|  | const tracer = /* retrieved from elsehwere in the package */ | ||
|  | const dc = require('diagnostics_channel') | ||
|  | const channel = dc.channel('fastify.initialization') | ||
|  | const spans = new WeakMap() | ||
|  | 
 | ||
|  | channel.subscribe(function ({ fastify }) { | ||
|  |   fastify.addHook('onRequest', (request, reply, done) => { | ||
|  |     const span = tracer.startSpan('fastify.request') | ||
|  |     spans.set(request, span) | ||
|  |     done() | ||
|  |   }) | ||
|  | 
 | ||
|  |   fastify.addHook('onResponse', (request, reply, done) => { | ||
|  |     const span = spans.get(request) | ||
|  |     span.finish() | ||
|  |     done() | ||
|  |   }) | ||
|  | }) | ||
|  | ``` |