node-fastify 5.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. package/.borp.yaml +3 -0
  2. package/.markdownlint-cli2.yaml +22 -0
  3. package/.prettierignore +1 -0
  4. package/GOVERNANCE.md +4 -0
  5. package/LICENSE +21 -0
  6. package/PROJECT_CHARTER.md +126 -0
  7. package/README.md +423 -0
  8. package/SECURITY.md +220 -0
  9. package/SPONSORS.md +24 -0
  10. package/build/build-error-serializer.js +35 -0
  11. package/build/build-validation.js +169 -0
  12. package/build/sync-version.js +11 -0
  13. package/docs/Guides/Benchmarking.md +60 -0
  14. package/docs/Guides/Database.md +321 -0
  15. package/docs/Guides/Delay-Accepting-Requests.md +608 -0
  16. package/docs/Guides/Detecting-When-Clients-Abort.md +172 -0
  17. package/docs/Guides/Ecosystem.md +726 -0
  18. package/docs/Guides/Fluent-Schema.md +127 -0
  19. package/docs/Guides/Getting-Started.md +620 -0
  20. package/docs/Guides/Index.md +43 -0
  21. package/docs/Guides/Migration-Guide-V3.md +287 -0
  22. package/docs/Guides/Migration-Guide-V4.md +267 -0
  23. package/docs/Guides/Migration-Guide-V5.md +727 -0
  24. package/docs/Guides/Plugins-Guide.md +520 -0
  25. package/docs/Guides/Prototype-Poisoning.md +383 -0
  26. package/docs/Guides/Recommendations.md +378 -0
  27. package/docs/Guides/Serverless.md +604 -0
  28. package/docs/Guides/Style-Guide.md +246 -0
  29. package/docs/Guides/Testing.md +481 -0
  30. package/docs/Guides/Write-Plugin.md +103 -0
  31. package/docs/Guides/Write-Type-Provider.md +34 -0
  32. package/docs/Reference/ContentTypeParser.md +271 -0
  33. package/docs/Reference/Decorators.md +436 -0
  34. package/docs/Reference/Encapsulation.md +194 -0
  35. package/docs/Reference/Errors.md +377 -0
  36. package/docs/Reference/HTTP2.md +94 -0
  37. package/docs/Reference/Hooks.md +958 -0
  38. package/docs/Reference/Index.md +73 -0
  39. package/docs/Reference/LTS.md +86 -0
  40. package/docs/Reference/Lifecycle.md +99 -0
  41. package/docs/Reference/Logging.md +268 -0
  42. package/docs/Reference/Middleware.md +79 -0
  43. package/docs/Reference/Plugins.md +245 -0
  44. package/docs/Reference/Principles.md +73 -0
  45. package/docs/Reference/Reply.md +1001 -0
  46. package/docs/Reference/Request.md +295 -0
  47. package/docs/Reference/Routes.md +802 -0
  48. package/docs/Reference/Server.md +2389 -0
  49. package/docs/Reference/Type-Providers.md +256 -0
  50. package/docs/Reference/TypeScript.md +1729 -0
  51. package/docs/Reference/Validation-and-Serialization.md +1130 -0
  52. package/docs/Reference/Warnings.md +58 -0
  53. package/docs/index.md +24 -0
  54. package/docs/resources/encapsulation_context.drawio +1 -0
  55. package/docs/resources/encapsulation_context.svg +3 -0
  56. package/eslint.config.js +35 -0
  57. package/examples/asyncawait.js +38 -0
  58. package/examples/benchmark/body.json +3 -0
  59. package/examples/benchmark/hooks-benchmark-async-await.js +44 -0
  60. package/examples/benchmark/hooks-benchmark.js +52 -0
  61. package/examples/benchmark/parser.js +47 -0
  62. package/examples/benchmark/simple.js +30 -0
  63. package/examples/benchmark/webstream.js +27 -0
  64. package/examples/hooks.js +91 -0
  65. package/examples/http2.js +39 -0
  66. package/examples/https.js +38 -0
  67. package/examples/parser.js +53 -0
  68. package/examples/plugin.js +12 -0
  69. package/examples/route-prefix.js +38 -0
  70. package/examples/shared-schema.js +38 -0
  71. package/examples/simple-stream.js +20 -0
  72. package/examples/simple.js +32 -0
  73. package/examples/simple.mjs +27 -0
  74. package/examples/typescript-server.ts +79 -0
  75. package/examples/use-plugin.js +29 -0
  76. package/fastify.d.ts +253 -0
  77. package/fastify.js +985 -0
  78. package/integration/server.js +29 -0
  79. package/integration/test.sh +23 -0
  80. package/lib/config-validator.js +1266 -0
  81. package/lib/content-type-parser.js +413 -0
  82. package/lib/content-type.js +160 -0
  83. package/lib/context.js +98 -0
  84. package/lib/decorate.js +152 -0
  85. package/lib/error-handler.js +173 -0
  86. package/lib/error-serializer.js +134 -0
  87. package/lib/error-status.js +14 -0
  88. package/lib/errors.js +516 -0
  89. package/lib/four-oh-four.js +190 -0
  90. package/lib/handle-request.js +195 -0
  91. package/lib/head-route.js +45 -0
  92. package/lib/hooks.js +429 -0
  93. package/lib/initial-config-validation.js +37 -0
  94. package/lib/logger-factory.js +136 -0
  95. package/lib/logger-pino.js +68 -0
  96. package/lib/noop-set.js +10 -0
  97. package/lib/plugin-override.js +90 -0
  98. package/lib/plugin-utils.js +169 -0
  99. package/lib/promise.js +23 -0
  100. package/lib/reply.js +1030 -0
  101. package/lib/req-id-gen-factory.js +52 -0
  102. package/lib/request.js +391 -0
  103. package/lib/route.js +686 -0
  104. package/lib/schema-controller.js +164 -0
  105. package/lib/schemas.js +207 -0
  106. package/lib/server.js +441 -0
  107. package/lib/symbols.js +71 -0
  108. package/lib/validation.js +280 -0
  109. package/lib/warnings.js +57 -0
  110. package/lib/wrap-thenable.js +84 -0
  111. package/package.json +225 -0
  112. package/scripts/validate-ecosystem-links.js +179 -0
  113. package/test/404s.test.js +2035 -0
  114. package/test/500s.test.js +422 -0
  115. package/test/allow-unsafe-regex.test.js +92 -0
  116. package/test/als.test.js +65 -0
  117. package/test/async-await.test.js +705 -0
  118. package/test/async-dispose.test.js +20 -0
  119. package/test/async_hooks.test.js +52 -0
  120. package/test/body-limit.test.js +224 -0
  121. package/test/buffer.test.js +74 -0
  122. package/test/build/error-serializer.test.js +36 -0
  123. package/test/build/version.test.js +14 -0
  124. package/test/build-certificate.js +109 -0
  125. package/test/bundler/README.md +29 -0
  126. package/test/bundler/esbuild/bundler-test.js +32 -0
  127. package/test/bundler/esbuild/package.json +10 -0
  128. package/test/bundler/esbuild/src/fail-plugin-version.js +14 -0
  129. package/test/bundler/esbuild/src/index.js +9 -0
  130. package/test/bundler/webpack/bundler-test.js +32 -0
  131. package/test/bundler/webpack/package.json +11 -0
  132. package/test/bundler/webpack/src/fail-plugin-version.js +14 -0
  133. package/test/bundler/webpack/src/index.js +9 -0
  134. package/test/bundler/webpack/webpack.config.js +15 -0
  135. package/test/case-insensitive.test.js +102 -0
  136. package/test/chainable.test.js +40 -0
  137. package/test/child-logger-factory.test.js +128 -0
  138. package/test/client-timeout.test.js +38 -0
  139. package/test/close-pipelining.test.js +78 -0
  140. package/test/close.test.js +706 -0
  141. package/test/conditional-pino.test.js +47 -0
  142. package/test/connection-timeout.test.js +42 -0
  143. package/test/constrained-routes.test.js +1138 -0
  144. package/test/content-length.test.js +174 -0
  145. package/test/content-parser.test.js +739 -0
  146. package/test/content-type.test.js +181 -0
  147. package/test/context-config.test.js +164 -0
  148. package/test/custom-http-server.test.js +118 -0
  149. package/test/custom-parser-async.test.js +59 -0
  150. package/test/custom-parser.0.test.js +701 -0
  151. package/test/custom-parser.1.test.js +266 -0
  152. package/test/custom-parser.2.test.js +91 -0
  153. package/test/custom-parser.3.test.js +208 -0
  154. package/test/custom-parser.4.test.js +218 -0
  155. package/test/custom-parser.5.test.js +130 -0
  156. package/test/custom-querystring-parser.test.js +129 -0
  157. package/test/decorator.test.js +1330 -0
  158. package/test/delete.test.js +344 -0
  159. package/test/diagnostics-channel/404.test.js +49 -0
  160. package/test/diagnostics-channel/async-delay-request.test.js +65 -0
  161. package/test/diagnostics-channel/async-request.test.js +64 -0
  162. package/test/diagnostics-channel/error-before-handler.test.js +35 -0
  163. package/test/diagnostics-channel/error-request.test.js +53 -0
  164. package/test/diagnostics-channel/error-status.test.js +123 -0
  165. package/test/diagnostics-channel/init.test.js +50 -0
  166. package/test/diagnostics-channel/sync-delay-request.test.js +49 -0
  167. package/test/diagnostics-channel/sync-request-reply.test.js +51 -0
  168. package/test/diagnostics-channel/sync-request.test.js +54 -0
  169. package/test/encapsulated-child-logger-factory.test.js +69 -0
  170. package/test/encapsulated-error-handler.test.js +237 -0
  171. package/test/esm/errorCodes.test.mjs +10 -0
  172. package/test/esm/esm.test.mjs +13 -0
  173. package/test/esm/index.test.js +8 -0
  174. package/test/esm/named-exports.mjs +14 -0
  175. package/test/esm/other.mjs +8 -0
  176. package/test/esm/plugin.mjs +8 -0
  177. package/test/fastify-instance.test.js +300 -0
  178. package/test/find-route.test.js +152 -0
  179. package/test/fluent-schema.test.js +209 -0
  180. package/test/genReqId.test.js +426 -0
  181. package/test/handler-context.test.js +45 -0
  182. package/test/handler-timeout.test.js +367 -0
  183. package/test/has-route.test.js +88 -0
  184. package/test/header-overflow.test.js +55 -0
  185. package/test/helper.js +496 -0
  186. package/test/hooks-async.test.js +1099 -0
  187. package/test/hooks.on-listen.test.js +1162 -0
  188. package/test/hooks.on-ready.test.js +421 -0
  189. package/test/hooks.test.js +3578 -0
  190. package/test/http-methods/copy.test.js +35 -0
  191. package/test/http-methods/custom-http-methods.test.js +114 -0
  192. package/test/http-methods/get.test.js +412 -0
  193. package/test/http-methods/head.test.js +263 -0
  194. package/test/http-methods/lock.test.js +108 -0
  195. package/test/http-methods/mkcalendar.test.js +143 -0
  196. package/test/http-methods/mkcol.test.js +35 -0
  197. package/test/http-methods/move.test.js +42 -0
  198. package/test/http-methods/propfind.test.js +136 -0
  199. package/test/http-methods/proppatch.test.js +105 -0
  200. package/test/http-methods/report.test.js +142 -0
  201. package/test/http-methods/search.test.js +233 -0
  202. package/test/http-methods/trace.test.js +21 -0
  203. package/test/http-methods/unlock.test.js +38 -0
  204. package/test/http2/closing.test.js +270 -0
  205. package/test/http2/constraint.test.js +109 -0
  206. package/test/http2/head.test.js +34 -0
  207. package/test/http2/plain.test.js +68 -0
  208. package/test/http2/secure-with-fallback.test.js +113 -0
  209. package/test/http2/secure.test.js +67 -0
  210. package/test/http2/unknown-http-method.test.js +34 -0
  211. package/test/https/custom-https-server.test.js +58 -0
  212. package/test/https/https.test.js +136 -0
  213. package/test/imports.test.js +17 -0
  214. package/test/inject.test.js +502 -0
  215. package/test/input-validation.js +335 -0
  216. package/test/internals/all.test.js +38 -0
  217. package/test/internals/content-type-parser.test.js +111 -0
  218. package/test/internals/context.test.js +31 -0
  219. package/test/internals/decorator.test.js +156 -0
  220. package/test/internals/errors.test.js +982 -0
  221. package/test/internals/handle-request.test.js +270 -0
  222. package/test/internals/hook-runner.test.js +449 -0
  223. package/test/internals/hooks.test.js +96 -0
  224. package/test/internals/initial-config.test.js +383 -0
  225. package/test/internals/logger.test.js +163 -0
  226. package/test/internals/plugin.test.js +170 -0
  227. package/test/internals/promise.test.js +63 -0
  228. package/test/internals/reply-serialize.test.js +714 -0
  229. package/test/internals/reply.test.js +1920 -0
  230. package/test/internals/req-id-gen-factory.test.js +133 -0
  231. package/test/internals/request-validate.test.js +1402 -0
  232. package/test/internals/request.test.js +506 -0
  233. package/test/internals/schema-controller-perf.test.js +40 -0
  234. package/test/internals/server.test.js +91 -0
  235. package/test/internals/validation.test.js +352 -0
  236. package/test/issue-4959.test.js +118 -0
  237. package/test/keep-alive-timeout.test.js +42 -0
  238. package/test/listen.1.test.js +154 -0
  239. package/test/listen.2.test.js +113 -0
  240. package/test/listen.3.test.js +83 -0
  241. package/test/listen.4.test.js +168 -0
  242. package/test/listen.5.test.js +122 -0
  243. package/test/logger/instantiation.test.js +341 -0
  244. package/test/logger/logger-test-utils.js +47 -0
  245. package/test/logger/logging.test.js +460 -0
  246. package/test/logger/options.test.js +579 -0
  247. package/test/logger/request.test.js +292 -0
  248. package/test/logger/response.test.js +183 -0
  249. package/test/logger/tap-parallel-not-ok +0 -0
  250. package/test/max-requests-per-socket.test.js +113 -0
  251. package/test/middleware.test.js +37 -0
  252. package/test/noop-set.test.js +19 -0
  253. package/test/nullable-validation.test.js +187 -0
  254. package/test/options.error-handler.test.js +5 -0
  255. package/test/options.test.js +5 -0
  256. package/test/output-validation.test.js +140 -0
  257. package/test/patch.error-handler.test.js +5 -0
  258. package/test/patch.test.js +5 -0
  259. package/test/plugin.1.test.js +230 -0
  260. package/test/plugin.2.test.js +314 -0
  261. package/test/plugin.3.test.js +287 -0
  262. package/test/plugin.4.test.js +504 -0
  263. package/test/plugin.helper.js +8 -0
  264. package/test/plugin.name.display.js +10 -0
  265. package/test/post-empty-body.test.js +38 -0
  266. package/test/pretty-print.test.js +366 -0
  267. package/test/promises.test.js +125 -0
  268. package/test/proto-poisoning.test.js +145 -0
  269. package/test/put.error-handler.test.js +5 -0
  270. package/test/put.test.js +5 -0
  271. package/test/register.test.js +184 -0
  272. package/test/reply-code.test.js +148 -0
  273. package/test/reply-early-hints.test.js +100 -0
  274. package/test/reply-error.test.js +815 -0
  275. package/test/reply-trailers.test.js +445 -0
  276. package/test/reply-web-stream-locked.test.js +37 -0
  277. package/test/request-error.test.js +624 -0
  278. package/test/request-header-host.test.js +339 -0
  279. package/test/request-id.test.js +118 -0
  280. package/test/request-timeout.test.js +53 -0
  281. package/test/route-hooks.test.js +635 -0
  282. package/test/route-prefix.test.js +904 -0
  283. package/test/route-shorthand.test.js +48 -0
  284. package/test/route.1.test.js +259 -0
  285. package/test/route.2.test.js +100 -0
  286. package/test/route.3.test.js +213 -0
  287. package/test/route.4.test.js +127 -0
  288. package/test/route.5.test.js +211 -0
  289. package/test/route.6.test.js +306 -0
  290. package/test/route.7.test.js +406 -0
  291. package/test/route.8.test.js +225 -0
  292. package/test/router-options.test.js +1108 -0
  293. package/test/same-shape.test.js +124 -0
  294. package/test/schema-examples.test.js +661 -0
  295. package/test/schema-feature.test.js +2198 -0
  296. package/test/schema-serialization.test.js +1171 -0
  297. package/test/schema-special-usage.test.js +1348 -0
  298. package/test/schema-validation.test.js +1572 -0
  299. package/test/scripts/validate-ecosystem-links.test.js +339 -0
  300. package/test/serialize-response.test.js +186 -0
  301. package/test/server.test.js +347 -0
  302. package/test/set-error-handler.test.js +69 -0
  303. package/test/skip-reply-send.test.js +317 -0
  304. package/test/stream-serializers.test.js +40 -0
  305. package/test/stream.1.test.js +94 -0
  306. package/test/stream.2.test.js +129 -0
  307. package/test/stream.3.test.js +198 -0
  308. package/test/stream.4.test.js +176 -0
  309. package/test/stream.5.test.js +188 -0
  310. package/test/sync-routes.test.js +32 -0
  311. package/test/throw.test.js +359 -0
  312. package/test/toolkit.js +63 -0
  313. package/test/trust-proxy.test.js +162 -0
  314. package/test/type-provider.test.js +22 -0
  315. package/test/types/content-type-parser.test-d.ts +72 -0
  316. package/test/types/decorate-request-reply.test-d.ts +18 -0
  317. package/test/types/dummy-plugin.ts +9 -0
  318. package/test/types/errors.test-d.ts +90 -0
  319. package/test/types/fastify.test-d.ts +352 -0
  320. package/test/types/hooks.test-d.ts +550 -0
  321. package/test/types/import.ts +2 -0
  322. package/test/types/instance.test-d.ts +588 -0
  323. package/test/types/logger.test-d.ts +277 -0
  324. package/test/types/plugin.test-d.ts +97 -0
  325. package/test/types/register.test-d.ts +237 -0
  326. package/test/types/reply.test-d.ts +254 -0
  327. package/test/types/request.test-d.ts +188 -0
  328. package/test/types/route.test-d.ts +553 -0
  329. package/test/types/schema.test-d.ts +135 -0
  330. package/test/types/serverFactory.test-d.ts +37 -0
  331. package/test/types/type-provider.test-d.ts +1213 -0
  332. package/test/types/using.test-d.ts +17 -0
  333. package/test/upgrade.test.js +52 -0
  334. package/test/url-rewriting.test.js +122 -0
  335. package/test/use-semicolon-delimiter.test.js +168 -0
  336. package/test/validation-error-handling.test.js +900 -0
  337. package/test/versioned-routes.test.js +603 -0
  338. package/test/web-api.test.js +616 -0
  339. package/test/wrap-thenable.test.js +30 -0
  340. package/types/content-type-parser.d.ts +75 -0
  341. package/types/context.d.ts +22 -0
  342. package/types/errors.d.ts +92 -0
  343. package/types/hooks.d.ts +875 -0
  344. package/types/instance.d.ts +609 -0
  345. package/types/logger.d.ts +107 -0
  346. package/types/plugin.d.ts +44 -0
  347. package/types/register.d.ts +42 -0
  348. package/types/reply.d.ts +81 -0
  349. package/types/request.d.ts +95 -0
  350. package/types/route.d.ts +199 -0
  351. package/types/schema.d.ts +61 -0
  352. package/types/server-factory.d.ts +19 -0
  353. package/types/type-provider.d.ts +130 -0
  354. package/types/utils.d.ts +98 -0
@@ -0,0 +1,958 @@
1
+ <h1 align="center">Fastify</h1>
2
+
3
+ ## Hooks
4
+
5
+ Hooks are registered with the `fastify.addHook` method and allow you to listen
6
+ to specific events in the application or request/response lifecycle. You have to
7
+ register a hook before the event is triggered, otherwise, the event is lost.
8
+
9
+ By using hooks you can interact directly with the lifecycle of Fastify. There
10
+ are Request/Reply hooks and application hooks:
11
+
12
+ - [Request/Reply Hooks](#requestreply-hooks)
13
+ - [onRequest](#onrequest)
14
+ - [preParsing](#preparsing)
15
+ - [preValidation](#prevalidation)
16
+ - [preHandler](#prehandler)
17
+ - [preSerialization](#preserialization)
18
+ - [onError](#onerror)
19
+ - [onSend](#onsend)
20
+ - [onResponse](#onresponse)
21
+ - [onTimeout](#ontimeout)
22
+ - [onRequestAbort](#onrequestabort)
23
+ - [Manage Errors from a hook](#manage-errors-from-a-hook)
24
+ - [Respond to a request from a hook](#respond-to-a-request-from-a-hook)
25
+ - [Application Hooks](#application-hooks)
26
+ - [onReady](#onready)
27
+ - [onListen](#onlisten)
28
+ - [onClose](#onclose)
29
+ - [preClose](#preclose)
30
+ - [onRoute](#onroute)
31
+ - [onRegister](#onregister)
32
+ - [Scope](#scope)
33
+ - [Route level hooks](#route-level-hooks)
34
+ - [Using Hooks to Inject Custom Properties](#using-hooks-to-inject-custom-properties)
35
+ - [Diagnostics Channel Hooks](#diagnostics-channel-hooks)
36
+
37
+ > ℹ️ Note:
38
+ > The `done` callback is not available when using `async`/`await` or
39
+ > returning a `Promise`. If you do invoke a `done` callback in this situation
40
+ > unexpected behavior may occur, e.g. duplicate invocation of handlers.
41
+
42
+ ## Request/Reply Hooks
43
+
44
+ [Request](./Request.md) and [Reply](./Reply.md) are the core Fastify objects.
45
+
46
+ `done` is the function to continue with the [lifecycle](./Lifecycle.md).
47
+
48
+ It is easy to understand where each hook is executed by looking at the
49
+ [lifecycle page](./Lifecycle.md).
50
+
51
+ Hooks are affected by Fastify's encapsulation, and can thus be applied to
52
+ selected routes. See the [Scopes](#scope) section for more information.
53
+
54
+ There are eight different hooks that you can use in Request/Reply *(in order of
55
+ execution)*:
56
+
57
+ ### onRequest
58
+ ```js
59
+ fastify.addHook('onRequest', (request, reply, done) => {
60
+ // Some code
61
+ done()
62
+ })
63
+ ```
64
+ Or `async/await`:
65
+ ```js
66
+ fastify.addHook('onRequest', async (request, reply) => {
67
+ // Some code
68
+ await asyncMethod()
69
+ })
70
+ ```
71
+
72
+ > ℹ️ Note:
73
+ > In the [onRequest](#onrequest) hook, `request.body` will always be
74
+ > `undefined`, because the body parsing happens before the
75
+ > [preValidation](#prevalidation) hook.
76
+
77
+ ### preParsing
78
+
79
+ If you are using the `preParsing` hook, you can transform the request payload
80
+ stream before it is parsed. It receives the request and reply objects as other
81
+ hooks, and a stream with the current request payload.
82
+
83
+ If it returns a value (via `return` or via the callback function), it must
84
+ return a stream.
85
+
86
+ For instance, you can decompress the request body:
87
+
88
+ ```js
89
+ fastify.addHook('preParsing', (request, reply, payload, done) => {
90
+ // Some code
91
+ done(null, newPayload)
92
+ })
93
+ ```
94
+ Or `async/await`:
95
+ ```js
96
+ fastify.addHook('preParsing', async (request, reply, payload) => {
97
+ // Some code
98
+ await asyncMethod()
99
+ return newPayload
100
+ })
101
+ ```
102
+
103
+ > ℹ️ Note:
104
+ > In the [preParsing](#preparsing) hook, `request.body` will always be
105
+ > `undefined`, because the body parsing happens before the
106
+ > [preValidation](#prevalidation) hook.
107
+
108
+ > ℹ️ Note:
109
+ > You should also add a `receivedEncodedLength` property to the
110
+ > returned stream. This property is used to correctly match the request payload
111
+ > with the `Content-Length` header value. Ideally, this property should be updated
112
+ > on each received chunk.
113
+
114
+ > ℹ️ Note:
115
+ > The size of the returned stream is checked to not exceed the limit
116
+ > set in [`bodyLimit`](./Server.md#bodylimit) option.
117
+
118
+ ### preValidation
119
+
120
+ If you are using the `preValidation` hook, you can change the payload before it
121
+ is validated. For example:
122
+
123
+ ```js
124
+ fastify.addHook('preValidation', (request, reply, done) => {
125
+ request.body = { ...request.body, importantKey: 'randomString' }
126
+ done()
127
+ })
128
+ ```
129
+ Or `async/await`:
130
+ ```js
131
+ fastify.addHook('preValidation', async (request, reply) => {
132
+ const importantKey = await generateRandomString()
133
+ request.body = { ...request.body, importantKey }
134
+ })
135
+ ```
136
+
137
+ ### preHandler
138
+
139
+ The `preHandler` hook allows you to specify a function that is executed before
140
+ a routes's handler.
141
+
142
+ ```js
143
+ fastify.addHook('preHandler', (request, reply, done) => {
144
+ // some code
145
+ done()
146
+ })
147
+ ```
148
+ Or `async/await`:
149
+ ```js
150
+ fastify.addHook('preHandler', async (request, reply) => {
151
+ // Some code
152
+ await asyncMethod()
153
+ })
154
+ ```
155
+ ### preSerialization
156
+
157
+ If you are using the `preSerialization` hook, you can change (or replace) the
158
+ payload before it is serialized. For example:
159
+
160
+ ```js
161
+ fastify.addHook('preSerialization', (request, reply, payload, done) => {
162
+ const err = null
163
+ const newPayload = { wrapped: payload }
164
+ done(err, newPayload)
165
+ })
166
+ ```
167
+ Or `async/await`:
168
+ ```js
169
+ fastify.addHook('preSerialization', async (request, reply, payload) => {
170
+ return { wrapped: payload }
171
+ })
172
+ ```
173
+
174
+ > ℹ️ Note:
175
+ > The hook is NOT called if the payload is a `string`, a `Buffer`, a
176
+ > `stream`, or `null`.
177
+
178
+ ### onError
179
+ ```js
180
+ fastify.addHook('onError', (request, reply, error, done) => {
181
+ // Some code
182
+ done()
183
+ })
184
+ ```
185
+ Or `async/await`:
186
+ ```js
187
+ fastify.addHook('onError', async (request, reply, error) => {
188
+ // Useful for custom error logging
189
+ // You should not use this hook to update the error
190
+ })
191
+ ```
192
+ This hook is useful if you need to do some custom error logging or add some
193
+ specific header in case of error.
194
+
195
+ It is not intended for changing the error, and calling `reply.send` will throw
196
+ an exception.
197
+
198
+ This hook will be executed before
199
+ the [Custom Error Handler set by `setErrorHandler`](./Server.md#seterrorhandler).
200
+
201
+ > ℹ️ Note:
202
+ > Unlike the other hooks, passing an error to the `done` function is not
203
+ > supported.
204
+
205
+ ### onSend
206
+ If you are using the `onSend` hook, you can change the payload. For example:
207
+
208
+ ```js
209
+ fastify.addHook('onSend', (request, reply, payload, done) => {
210
+ const err = null;
211
+ const newPayload = payload.replace('some-text', 'some-new-text')
212
+ done(err, newPayload)
213
+ })
214
+ ```
215
+ Or `async/await`:
216
+ ```js
217
+ fastify.addHook('onSend', async (request, reply, payload) => {
218
+ const newPayload = payload.replace('some-text', 'some-new-text')
219
+ return newPayload
220
+ })
221
+ ```
222
+
223
+ You can also clear the payload to send a response with an empty body by
224
+ replacing the payload with `null`:
225
+
226
+ ```js
227
+ fastify.addHook('onSend', (request, reply, payload, done) => {
228
+ reply.code(304)
229
+ const newPayload = null
230
+ done(null, newPayload)
231
+ })
232
+ ```
233
+
234
+ > You can also send an empty body by replacing the payload with the empty string
235
+ > `''`, but be aware that this will cause the `Content-Length` header to be set
236
+ > to `0`, whereas the `Content-Length` header will not be set if the payload is
237
+ > `null`.
238
+
239
+ > ℹ️ Note:
240
+ > If you change the payload, you may only change it to a `string`, a
241
+ > `Buffer`, a `stream`, a `ReadableStream`, a `Response`, or `null`.
242
+
243
+
244
+ ### onResponse
245
+ ```js
246
+ fastify.addHook('onResponse', (request, reply, done) => {
247
+ // Some code
248
+ done()
249
+ })
250
+ ```
251
+ Or `async/await`:
252
+ ```js
253
+ fastify.addHook('onResponse', async (request, reply) => {
254
+ // Some code
255
+ await asyncMethod()
256
+ })
257
+ ```
258
+
259
+ The `onResponse` hook is executed when a response has been sent, so you will not
260
+ be able to send more data to the client. It can however be useful for sending
261
+ data to external services, for example, to gather statistics.
262
+
263
+ > ℹ️ Note:
264
+ > Setting `disableRequestLogging` to `true` will disable any error log
265
+ > inside the `onResponse` hook. In this case use `try - catch` to log errors.
266
+
267
+ ### onTimeout
268
+
269
+ ```js
270
+ fastify.addHook('onTimeout', (request, reply, done) => {
271
+ // Some code
272
+ done()
273
+ })
274
+ ```
275
+ Or `async/await`:
276
+ ```js
277
+ fastify.addHook('onTimeout', async (request, reply) => {
278
+ // Some code
279
+ await asyncMethod()
280
+ })
281
+ ```
282
+ `onTimeout` is useful if you need to monitor the request timed out in your
283
+ service (if the `connectionTimeout` property is set on the Fastify instance).
284
+ The `onTimeout` hook is executed when a request is timed out and the HTTP socket
285
+ has been hung up. Therefore, you will not be able to send data to the client.
286
+
287
+ > ℹ️ Note:
288
+ > The `onTimeout` hook is triggered by socket-level timeouts set via
289
+ > `connectionTimeout`. For application-level per-route timeouts, see the
290
+ > [`handlerTimeout`](./Server.md#factory-handler-timeout) option which uses
291
+ > `request.signal` for cooperative cancellation.
292
+
293
+ ### onRequestAbort
294
+
295
+ ```js
296
+ fastify.addHook('onRequestAbort', (request, done) => {
297
+ // Some code
298
+ done()
299
+ })
300
+ ```
301
+ Or `async/await`:
302
+ ```js
303
+ fastify.addHook('onRequestAbort', async (request) => {
304
+ // Some code
305
+ await asyncMethod()
306
+ })
307
+ ```
308
+ The `onRequestAbort` hook is executed when a client closes the connection before
309
+ the entire request has been processed. Therefore, you will not be able to send
310
+ data to the client.
311
+
312
+ > ℹ️ Note:
313
+ > Client abort detection is not completely reliable.
314
+ > See: [`Detecting-When-Clients-Abort.md`](../Guides/Detecting-When-Clients-Abort.md)
315
+
316
+ ### Manage Errors from a hook
317
+ If you get an error during the execution of your hook, just pass it to `done()`
318
+ and Fastify will automatically close the request and send the appropriate error
319
+ code to the user.
320
+
321
+ ```js
322
+ fastify.addHook('onRequest', (request, reply, done) => {
323
+ done(new Error('Some error'))
324
+ })
325
+ ```
326
+
327
+ If you want to pass a custom error code to the user, just use `reply.code()`:
328
+ ```js
329
+ fastify.addHook('preHandler', (request, reply, done) => {
330
+ reply.code(400)
331
+ done(new Error('Some error'))
332
+ })
333
+ ```
334
+ *The error will be handled by [`Reply`](./Reply.md#errors).*
335
+
336
+ Or if you're using `async/await` you can just throw an error:
337
+ ```js
338
+ fastify.addHook('onRequest', async (request, reply) => {
339
+ throw new Error('Some error')
340
+ })
341
+ ```
342
+
343
+ ### Respond to a request from a hook
344
+
345
+ If needed, you can respond to a request before you reach the route handler, for
346
+ example when implementing an authentication hook. Replying from a hook implies
347
+ that the hook chain is __stopped__ and the rest of the hooks and handlers are
348
+ not executed. If the hook is using the callback approach, i.e. it is not an
349
+ `async` function or it returns a `Promise`, it is as simple as calling
350
+ `reply.send()` and avoiding calling the callback. If the hook is `async`,
351
+ `reply.send()` __must__ be called _before_ the function returns or the promise
352
+ resolves, otherwise, the request will proceed. When `reply.send()` is called
353
+ outside of the promise chain, it is important to `return reply` otherwise the
354
+ request will be executed twice.
355
+
356
+ It is important to __not mix callbacks and `async`/`Promise`__, otherwise the
357
+ hook chain will be executed twice.
358
+
359
+ If you are using `onRequest` or `preHandler` use `reply.send`.
360
+
361
+ ```js
362
+ fastify.addHook('onRequest', (request, reply, done) => {
363
+ reply.send('Early response')
364
+ })
365
+
366
+ // Works with async functions too
367
+ fastify.addHook('preHandler', async (request, reply) => {
368
+ setTimeout(() => {
369
+ reply.send({ hello: 'from prehandler' })
370
+ })
371
+ return reply // mandatory, so the request is not executed further
372
+ // Commenting the line above will allow the hooks to continue and fail with FST_ERR_REP_ALREADY_SENT
373
+ })
374
+ ```
375
+
376
+ If you want to respond with a stream, you should avoid using an `async` function
377
+ for the hook. If you must use an `async` function, your code will need to follow
378
+ the pattern in
379
+ [test/hooks-async.js](https://github.com/fastify/fastify/blob/94ea67ef2d8dce8a955d510cd9081aabd036fa85/test/hooks-async.js#L269-L275).
380
+
381
+ ```js
382
+ fastify.addHook('onRequest', (request, reply, done) => {
383
+ const stream = fs.createReadStream('some-file', 'utf8')
384
+ reply.send(stream)
385
+ })
386
+ ```
387
+
388
+ If you are sending a response without `await` on it, make sure to always `return
389
+ reply`:
390
+
391
+ ```js
392
+ fastify.addHook('preHandler', async (request, reply) => {
393
+ setImmediate(() => { reply.send('hello') })
394
+
395
+ // This is needed to signal the handler to wait for a response
396
+ // to be sent outside of the promise chain
397
+ return reply
398
+ })
399
+
400
+ fastify.addHook('preHandler', async (request, reply) => {
401
+ // the @fastify/static plugin will send a file asynchronously,
402
+ // so we should return reply
403
+ reply.sendFile('myfile')
404
+ return reply
405
+ })
406
+ ```
407
+
408
+ ## Application Hooks
409
+
410
+ You can hook into the application-lifecycle as well.
411
+
412
+ - [onReady](#onready)
413
+ - [onListen](#onlisten)
414
+ - [onClose](#onclose)
415
+ - [preClose](#preclose)
416
+ - [onRoute](#onroute)
417
+ - [onRegister](#onregister)
418
+
419
+ ### onReady
420
+ Triggered before the server starts listening for requests and when `.ready()` is
421
+ invoked. It cannot change the routes or add new hooks. Registered hook functions
422
+ are executed serially. Only after all `onReady` hook functions have completed
423
+ will the server start listening for requests. Hook functions accept one
424
+ argument: a callback, `done`, to be invoked after the hook function is complete.
425
+ Hook functions are invoked with `this` bound to the associated Fastify instance.
426
+
427
+ ```js
428
+ // callback style
429
+ fastify.addHook('onReady', function (done) {
430
+ // Some code
431
+ const err = null;
432
+ done(err)
433
+ })
434
+
435
+ // or async/await style
436
+ fastify.addHook('onReady', async function () {
437
+ // Some async code
438
+ await loadCacheFromDatabase()
439
+ })
440
+ ```
441
+
442
+ ### onListen
443
+
444
+ Triggered when the server starts listening for requests. The hooks run one
445
+ after another. If a hook function causes an error, it is logged and
446
+ ignored, allowing the queue of hooks to continue. Hook functions accept one
447
+ argument: a callback, `done`, to be invoked after the hook function is
448
+ complete. Hook functions are invoked with `this` bound to the associated
449
+ Fastify instance.
450
+
451
+ This is an alternative to `fastify.server.on('listening', () => {})`.
452
+
453
+ ```js
454
+ // callback style
455
+ fastify.addHook('onListen', function (done) {
456
+ // Some code
457
+ const err = null;
458
+ done(err)
459
+ })
460
+
461
+ // or async/await style
462
+ fastify.addHook('onListen', async function () {
463
+ // Some async code
464
+ })
465
+ ```
466
+
467
+ > ℹ️ Note:
468
+ > This hook will not run when the server is started using
469
+ > `fastify.inject()` or `fastify.ready()`.
470
+
471
+ ### onClose
472
+ <a id="on-close"></a>
473
+
474
+ Triggered when `fastify.close()` is invoked to stop the server. By the time
475
+ `onClose` hooks execute, the HTTP server has already stopped listening, all
476
+ in-flight HTTP requests have been completed, and connections have been drained.
477
+ This makes `onClose` the safe place for [plugins](./Plugins.md) to release
478
+ resources such as database connection pools, as no new requests will
479
+ arrive.
480
+
481
+ The hook function takes the Fastify instance as a first argument,
482
+ and a `done` callback for synchronous hook functions.
483
+ ```js
484
+ // callback style
485
+ fastify.addHook('onClose', (instance, done) => {
486
+ // Some code
487
+ done()
488
+ })
489
+
490
+ // or async/await style
491
+ fastify.addHook('onClose', async (instance) => {
492
+ // Some async code
493
+ await closeDatabaseConnections()
494
+ })
495
+ ```
496
+
497
+ #### Execution order
498
+
499
+ When multiple `onClose` hooks are registered across plugins, child-plugin hooks
500
+ execute before parent-plugin hooks. This means a database plugin's `onClose`
501
+ hook will run before the root-level `onClose` hooks:
502
+
503
+ ```js
504
+ fastify.register(function dbPlugin (instance, opts, done) {
505
+ instance.addHook('onClose', async (instance) => {
506
+ // Runs first — close the database pool
507
+ await instance.db.close()
508
+ })
509
+ done()
510
+ })
511
+
512
+ fastify.addHook('onClose', async (instance) => {
513
+ // Runs second — after child plugins have cleaned up
514
+ })
515
+ ```
516
+
517
+ See [`close`](./Server.md#close) for the full shutdown lifecycle.
518
+
519
+ ### preClose
520
+ <a id="pre-close"></a>
521
+
522
+ Triggered when `fastify.close()` is invoked to stop the server. At this
523
+ point the server is already rejecting new requests with `503` (when
524
+ [`return503OnClosing`](./Server.md#factory-return-503-on-closing) is `true`),
525
+ but the HTTP server has not yet stopped listening and in-flight requests are
526
+ still being processed.
527
+
528
+ It is useful when [plugins](./Plugins.md) have set up state attached to the HTTP
529
+ server that would prevent the server from closing, such as open WebSocket
530
+ connections or Server-Sent Events streams that must be explicitly terminated for
531
+ `server.close()` to complete.
532
+ _It is unlikely you will need to use this hook_,
533
+ use the [`onClose`](#onclose) for the most common case.
534
+
535
+ ```js
536
+ // callback style
537
+ fastify.addHook('preClose', (done) => {
538
+ // Some code
539
+ done()
540
+ })
541
+
542
+ // or async/await style
543
+ fastify.addHook('preClose', async () => {
544
+ // Some async code
545
+ await removeSomeServerState()
546
+ })
547
+ ```
548
+
549
+ For example, closing WebSocket connections during shutdown:
550
+
551
+ ```js
552
+ fastify.addHook('preClose', async () => {
553
+ // Close all WebSocket connections so that server.close() can complete.
554
+ // Without this, open connections would keep the server alive.
555
+ for (const ws of activeWebSockets) {
556
+ ws.close(1001, 'Server shutting down')
557
+ }
558
+ })
559
+ ```
560
+
561
+ ### onRoute
562
+ <a id="on-route"></a>
563
+
564
+ Triggered when a new route is registered. Listeners are passed a [`routeOptions`](./Routes.md#routes-options)
565
+ object as the sole parameter. The interface is synchronous, and, as such, the
566
+ listeners are not passed a callback. This hook is encapsulated.
567
+
568
+ ```js
569
+ fastify.addHook('onRoute', (routeOptions) => {
570
+ //Some code
571
+ routeOptions.method
572
+ routeOptions.schema
573
+ routeOptions.url // the complete URL of the route, it will include the prefix if any
574
+ routeOptions.path // `url` alias
575
+ routeOptions.routePath // the URL of the route without the prefix
576
+ routeOptions.bodyLimit
577
+ routeOptions.logLevel
578
+ routeOptions.logSerializers
579
+ routeOptions.prefix
580
+ })
581
+ ```
582
+
583
+ If you are authoring a plugin and you need to customize application routes, like
584
+ modifying the options or adding new route hooks, this is the right place.
585
+
586
+ ```js
587
+ fastify.addHook('onRoute', (routeOptions) => {
588
+ function onPreSerialization(request, reply, payload, done) {
589
+ // Your code
590
+ done(null, payload)
591
+ }
592
+ // preSerialization can be an array or undefined
593
+ routeOptions.preSerialization = [...(routeOptions.preSerialization || []), onPreSerialization]
594
+ })
595
+ ```
596
+
597
+ To add more routes within an onRoute hook, the routes must
598
+ be tagged correctly. The hook will run into an infinite loop if
599
+ not tagged. The recommended approach is shown below.
600
+
601
+ ```js
602
+ const kRouteAlreadyProcessed = Symbol('route-already-processed')
603
+
604
+ fastify.addHook('onRoute', function (routeOptions) {
605
+ const { url, method } = routeOptions
606
+
607
+ const isAlreadyProcessed = (routeOptions.custom && routeOptions.custom[kRouteAlreadyProcessed]) || false
608
+
609
+ if (!isAlreadyProcessed) {
610
+ this.route({
611
+ url,
612
+ method,
613
+ custom: {
614
+ [kRouteAlreadyProcessed]: true
615
+ },
616
+ handler: () => {}
617
+ })
618
+ }
619
+ })
620
+ ```
621
+
622
+ For more details, see this [issue](https://github.com/fastify/fastify/issues/4319).
623
+
624
+ ### onRegister
625
+ <a id="on-register"></a>
626
+
627
+ Triggered when a new plugin is registered and a new encapsulation context is
628
+ created. The hook will be executed **before** the registered code.
629
+
630
+ This hook can be useful if you are developing a plugin that needs to know when a
631
+ plugin context is formed, and you want to operate in that specific context, thus
632
+ this hook is encapsulated.
633
+
634
+ > ℹ️ Note:
635
+ > This hook will not be called if a plugin is wrapped inside
636
+ > [`fastify-plugin`](https://github.com/fastify/fastify-plugin).
637
+ ```js
638
+ fastify.decorate('data', [])
639
+
640
+ fastify.register(async (instance, opts) => {
641
+ instance.data.push('hello')
642
+ console.log(instance.data) // ['hello']
643
+
644
+ instance.register(async (instance, opts) => {
645
+ instance.data.push('world')
646
+ console.log(instance.data) // ['hello', 'world']
647
+ }, { prefix: '/hola' })
648
+ }, { prefix: '/ciao' })
649
+
650
+ fastify.register(async (instance, opts) => {
651
+ console.log(instance.data) // []
652
+ }, { prefix: '/hello' })
653
+
654
+ fastify.addHook('onRegister', (instance, opts) => {
655
+ // Create a new array from the old one
656
+ // but without keeping the reference
657
+ // allowing the user to have encapsulated
658
+ // instances of the `data` property
659
+ instance.data = instance.data.slice()
660
+
661
+ // the options of the new registered instance
662
+ console.log(opts.prefix)
663
+ })
664
+ ```
665
+
666
+ ## Scope
667
+ <a id="scope"></a>
668
+
669
+ Except for [onClose](#onclose), all hooks are encapsulated. This means that you
670
+ can decide where your hooks should run by using `register` as explained in the
671
+ [plugins guide](../Guides/Plugins-Guide.md). If you pass a function, that
672
+ function is bound to the right Fastify context and from there you have full
673
+ access to the Fastify API.
674
+
675
+ ```js
676
+ fastify.addHook('onRequest', function (request, reply, done) {
677
+ const self = this // Fastify context
678
+ done()
679
+ })
680
+ ```
681
+
682
+ Note that the Fastify context in each hook is the same as the plugin where the
683
+ route was registered, for example:
684
+
685
+ ```js
686
+ fastify.addHook('onRequest', async function (req, reply) {
687
+ if (req.raw.url === '/nested') {
688
+ assert.strictEqual(this.foo, 'bar')
689
+ } else {
690
+ assert.strictEqual(this.foo, undefined)
691
+ }
692
+ })
693
+
694
+ fastify.get('/', async function (req, reply) {
695
+ assert.strictEqual(this.foo, undefined)
696
+ return { hello: 'world' }
697
+ })
698
+
699
+ fastify.register(async function plugin (fastify, opts) {
700
+ fastify.decorate('foo', 'bar')
701
+
702
+ fastify.get('/nested', async function (req, reply) {
703
+ assert.strictEqual(this.foo, 'bar')
704
+ return { hello: 'world' }
705
+ })
706
+ })
707
+ ```
708
+
709
+ Warn: if you declare the function with an [arrow
710
+ function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions),
711
+ the `this` will not be Fastify, but the one of the current scope.
712
+
713
+
714
+ ## Route level hooks
715
+ <a id="route-hooks"></a>
716
+
717
+ You can declare one or more custom lifecycle hooks ([onRequest](#onrequest),
718
+ [onResponse](#onresponse), [preParsing](#preparsing),
719
+ [preValidation](#prevalidation), [preHandler](#prehandler),
720
+ [preSerialization](#preserialization), [onSend](#onsend),
721
+ [onTimeout](#ontimeout), and [onError](#onerror)) hook(s) that will be
722
+ **unique** for the route. If you do so, those hooks are always executed as the
723
+ last hook in their category.
724
+
725
+ This can be useful if you need to implement authentication, where the
726
+ [preParsing](#preparsing) or [preValidation](#prevalidation) hooks are exactly
727
+ what you need. Multiple route-level hooks can also be specified as an array.
728
+
729
+ ```js
730
+ fastify.addHook('onRequest', (request, reply, done) => {
731
+ // Your code
732
+ done()
733
+ })
734
+
735
+ fastify.addHook('onResponse', (request, reply, done) => {
736
+ // your code
737
+ done()
738
+ })
739
+
740
+ fastify.addHook('preParsing', (request, reply, done) => {
741
+ // Your code
742
+ done()
743
+ })
744
+
745
+ fastify.addHook('preValidation', (request, reply, done) => {
746
+ // Your code
747
+ done()
748
+ })
749
+
750
+ fastify.addHook('preHandler', (request, reply, done) => {
751
+ // Your code
752
+ done()
753
+ })
754
+
755
+ fastify.addHook('preSerialization', (request, reply, payload, done) => {
756
+ // Your code
757
+ done(null, payload)
758
+ })
759
+
760
+ fastify.addHook('onSend', (request, reply, payload, done) => {
761
+ // Your code
762
+ done(null, payload)
763
+ })
764
+
765
+ fastify.addHook('onTimeout', (request, reply, done) => {
766
+ // Your code
767
+ done()
768
+ })
769
+
770
+ fastify.addHook('onError', (request, reply, error, done) => {
771
+ // Your code
772
+ done()
773
+ })
774
+
775
+ fastify.route({
776
+ method: 'GET',
777
+ url: '/',
778
+ schema: { ... },
779
+ onRequest: function (request, reply, done) {
780
+ // This hook will always be executed after the shared `onRequest` hooks
781
+ done()
782
+ },
783
+ // // Example with an async hook. All hooks support this syntax
784
+ //
785
+ // onRequest: async function (request, reply) {
786
+ // // This hook will always be executed after the shared `onRequest` hooks
787
+ // await ...
788
+ // }
789
+ onResponse: function (request, reply, done) {
790
+ // this hook will always be executed after the shared `onResponse` hooks
791
+ done()
792
+ },
793
+ preParsing: function (request, reply, done) {
794
+ // This hook will always be executed after the shared `preParsing` hooks
795
+ done()
796
+ },
797
+ preValidation: function (request, reply, done) {
798
+ // This hook will always be executed after the shared `preValidation` hooks
799
+ done()
800
+ },
801
+ preHandler: function (request, reply, done) {
802
+ // This hook will always be executed after the shared `preHandler` hooks
803
+ done()
804
+ },
805
+ // // Example with an array. All hooks support this syntax.
806
+ //
807
+ // preHandler: [function (request, reply, done) {
808
+ // // This hook will always be executed after the shared `preHandler` hooks
809
+ // done()
810
+ // }],
811
+ preSerialization: (request, reply, payload, done) => {
812
+ // This hook will always be executed after the shared `preSerialization` hooks
813
+ done(null, payload)
814
+ },
815
+ onSend: (request, reply, payload, done) => {
816
+ // This hook will always be executed after the shared `onSend` hooks
817
+ done(null, payload)
818
+ },
819
+ onTimeout: (request, reply, done) => {
820
+ // This hook will always be executed after the shared `onTimeout` hooks
821
+ done()
822
+ },
823
+ onError: (request, reply, error, done) => {
824
+ // This hook will always be executed after the shared `onError` hooks
825
+ done()
826
+ },
827
+ handler: function (request, reply) {
828
+ reply.send({ hello: 'world' })
829
+ }
830
+ })
831
+ ```
832
+
833
+ > ℹ️ Note:
834
+ > Both options also accept an array of functions.
835
+
836
+ ## Using Hooks to Inject Custom Properties
837
+ <a id="using-hooks-to-inject-custom-properties"></a>
838
+
839
+ You can use a hook to inject custom properties into incoming requests.
840
+ This is useful for reusing processed data from hooks in controllers.
841
+
842
+ A very common use case is, for example, checking user authentication based
843
+ on their token and then storing their recovered data into
844
+ the [Request](./Request.md) instance. This way, your controllers can read it
845
+ easily with `request.authenticatedUser` or whatever you want to call it.
846
+ That's how it might look like:
847
+
848
+ ```js
849
+ fastify.addHook('preParsing', async (request) => {
850
+ request.authenticatedUser = {
851
+ id: 42,
852
+ name: 'Jane Doe',
853
+ role: 'admin'
854
+ }
855
+ })
856
+
857
+ fastify.get('/me/is-admin', async function (req, reply) {
858
+ return { isAdmin: req.authenticatedUser?.role === 'admin' || false }
859
+ })
860
+ ```
861
+
862
+ Note that `.authenticatedUser` could actually be any property name
863
+ chosen by yourself. Using your own custom property prevents you
864
+ from mutating existing properties, which
865
+ would be a dangerous and destructive operation. So be careful and
866
+ make sure your property is entirely new, also using this approach
867
+ only for very specific and small cases like this example.
868
+
869
+ Regarding TypeScript in this example, you'd need to update the
870
+ `FastifyRequest` core interface to include your new property typing
871
+ (for more about it, see [TypeScript](./TypeScript.md) page), like:
872
+
873
+ ```ts
874
+ interface AuthenticatedUser { /* ... */ }
875
+
876
+ declare module 'fastify' {
877
+ export interface FastifyRequest {
878
+ authenticatedUser?: AuthenticatedUser;
879
+ }
880
+ }
881
+ ```
882
+
883
+ Although this is a very pragmatic approach, if you're trying to do
884
+ something more complex that changes these core objects, then
885
+ consider creating a custom [Plugin](./Plugins.md) instead.
886
+
887
+ ## Diagnostics Channel Hooks
888
+
889
+ One [`diagnostics_channel`](https://nodejs.org/api/diagnostics_channel.html)
890
+ publish event, `'fastify.initialization'`, happens at initialization time. The
891
+ Fastify instance is passed into the hook as a property of the object passed in.
892
+ At this point, the instance can be interacted with to add hooks, plugins,
893
+ routes, or any other sort of modification.
894
+
895
+ For example, a tracing package might do something like the following (which is,
896
+ of course, a simplification). This would be in a file loaded in the
897
+ initialization of the tracking package, in the typical "require instrumentation
898
+ tools first" fashion.
899
+
900
+ ```js
901
+ const tracer = /* retrieved from elsewhere in the package */
902
+ const dc = require('node:diagnostics_channel')
903
+ const channel = dc.channel('fastify.initialization')
904
+ const spans = new WeakMap()
905
+
906
+ channel.subscribe(function ({ fastify }) {
907
+ fastify.addHook('onRequest', (request, reply, done) => {
908
+ const span = tracer.startSpan('fastify.request.handler')
909
+ spans.set(request, span)
910
+ done()
911
+ })
912
+
913
+ fastify.addHook('onResponse', (request, reply, done) => {
914
+ const span = spans.get(request)
915
+ span.finish()
916
+ done()
917
+ })
918
+ })
919
+ ```
920
+
921
+ > ℹ️ Note:
922
+ > The TracingChannel class API is currently experimental and may undergo
923
+ > breaking changes even in semver-patch releases of Node.js.
924
+
925
+ Five other events are published on a per-request basis following the
926
+ [Tracing Channel](https://nodejs.org/api/diagnostics_channel.html#class-tracingchannel)
927
+ nomenclature. The list of the channel names and the event they receive is:
928
+
929
+ - `tracing:fastify.request.handler:start`: Always fires
930
+ - `{ request: Request, reply: Reply, route: { url, method } }`
931
+ - `tracing:fastify.request.handler:end`: Always fires
932
+ - `{ request: Request, reply: Reply, route: { url, method }, async: Bool }`
933
+ - `tracing:fastify.request.handler:asyncStart`: Fires for promise/async handlers
934
+ - `{ request: Request, reply: Reply, route: { url, method } }`
935
+ - `tracing:fastify.request.handler:asyncEnd`: Fires for promise/async handlers
936
+ - `{ request: Request, reply: Reply, route: { url, method } }`
937
+ - `tracing:fastify.request.handler:error`: Fires when an error occurs
938
+ - `{ request: Request, reply: Reply, route: { url, method }, error: Error }`
939
+
940
+ The object instance remains the same for all events associated with a given
941
+ request. All payloads include a `request` and `reply` property which are an
942
+ instance of Fastify's `Request` and `Reply` instances. They also include a
943
+ `route` property which is an object with the matched `url` pattern (e.g.
944
+ `/collection/:id`) and the `method` HTTP method (e.g. `GET`). The `:start` and
945
+ `:end` events always fire for requests. If a request handler is an `async`
946
+ function or one that returns a `Promise` then the `:asyncStart` and `:asyncEnd`
947
+ events also fire. Finally, the `:error` event contains an `error` property
948
+ associated with the request's failure.
949
+
950
+ These events can be received like so:
951
+
952
+ ```js
953
+ const dc = require('node:diagnostics_channel')
954
+ const channel = dc.channel('tracing:fastify.request.handler:start')
955
+ channel.subscribe((msg) => {
956
+ console.log(msg.request, msg.reply)
957
+ })
958
+ ```