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,436 @@
1
+ <h1 align="center">Fastify</h1>
2
+
3
+ ## Decorators
4
+
5
+ The decorators API customizes core Fastify objects, such as the server instance
6
+ and any request and reply objects used during the HTTP request lifecycle. It
7
+ can attach any type of property to core objects, e.g., functions, plain
8
+ objects, or native types.
9
+
10
+ This API is *synchronous*. Defining a decoration asynchronously could result in
11
+ the Fastify instance booting before the decoration completes. To register an
12
+ asynchronous decoration, use the `register` API with `fastify-plugin`. See the
13
+ [Plugins](./Plugins.md) documentation for more details.
14
+
15
+ Decorating core objects with this API allows the underlying JavaScript engine to
16
+ optimize the handling of server, request, and reply objects. This is
17
+ accomplished by defining the shape of all such object instances before they are
18
+ instantiated and used. As an example, the following is not recommended because
19
+ it will change the shape of objects during their lifecycle:
20
+
21
+ ```js
22
+ // Bad example! Continue reading.
23
+
24
+ // Attach a user property to the incoming request before the request
25
+ // handler is invoked.
26
+ fastify.addHook('preHandler', function (req, reply, done) {
27
+ req.user = 'Bob Dylan'
28
+ done()
29
+ })
30
+
31
+ // Use the attached user property in the request handler.
32
+ fastify.get('/', function (req, reply) {
33
+ reply.send(`Hello, ${req.user}`)
34
+ })
35
+ ```
36
+
37
+ The above example mutates the request object after instantiation, causing the
38
+ JavaScript engine to deoptimize access. Using the decoration API avoids this
39
+ deoptimization:
40
+
41
+ ```js
42
+ // Decorate request with a 'user' property
43
+ fastify.decorateRequest('user', '')
44
+
45
+ // Update our property
46
+ fastify.addHook('preHandler', (req, reply, done) => {
47
+ req.user = 'Bob Dylan'
48
+ done()
49
+ })
50
+ // And finally access it
51
+ fastify.get('/', (req, reply) => {
52
+ reply.send(`Hello, ${req.user}!`)
53
+ })
54
+ ```
55
+
56
+ Keep the initial shape of a decorated field close to its future dynamic value.
57
+ Initialize a decorator as `''` for strings and `null` for objects or functions.
58
+ This works only with value types; reference types will throw an error during
59
+ Fastify startup. See [decorateRequest](#decorate-request) and
60
+ [JavaScript engine fundamentals: Shapes
61
+ and Inline Caches](https://mathiasbynens.be/notes/shapes-ics)
62
+ for more information.
63
+
64
+ ### Usage
65
+ <a id="usage"></a>
66
+
67
+ #### `decorate(name, value, [dependencies])`
68
+ <a id="decorate"></a>
69
+
70
+ This method customizes the Fastify [server](./Server.md) instance.
71
+
72
+ For example, to attach a new method to the server instance:
73
+
74
+ ```js
75
+ fastify.decorate('utility', function () {
76
+ // Something very useful
77
+ })
78
+ ```
79
+
80
+ Non-function values can also be attached to the server instance:
81
+
82
+ ```js
83
+ fastify.decorate('conf', {
84
+ db: 'some.db',
85
+ port: 3000
86
+ })
87
+ ```
88
+
89
+ To access decorated properties, use the name provided to the decoration API:
90
+
91
+ ```js
92
+ fastify.utility()
93
+
94
+ console.log(fastify.conf.db)
95
+ ```
96
+
97
+ The decorated [Fastify server](./Server.md) is bound to `this` in
98
+ [route](./Routes.md) handlers:
99
+
100
+ ```js
101
+ fastify.decorate('db', new DbConnection())
102
+
103
+ fastify.get('/', async function (request, reply) {
104
+ // using return
105
+ return { hello: await this.db.query('world') }
106
+
107
+ // or
108
+ // using reply.send()
109
+ reply.send({ hello: await this.db.query('world') })
110
+ await reply
111
+ })
112
+ ```
113
+
114
+ The `dependencies` parameter is an optional list of decorators that the
115
+ decorator being defined relies upon. This list contains the names of other
116
+ decorators. In the following example, the "utility" decorator depends on the
117
+ "greet" and "hi" decorators:
118
+
119
+ ```js
120
+ async function greetDecorator (fastify, opts) {
121
+ fastify.decorate('greet', () => {
122
+ return 'greet message'
123
+ })
124
+ }
125
+
126
+ async function hiDecorator (fastify, opts) {
127
+ fastify.decorate('hi', () => {
128
+ return 'hi message'
129
+ })
130
+ }
131
+
132
+ async function utilityDecorator (fastify, opts) {
133
+ fastify.decorate('utility', () => {
134
+ return `${fastify.greet()} | ${fastify.hi()}`
135
+ })
136
+ }
137
+
138
+ fastify.register(fastifyPlugin(greetDecorator, { name: 'greet' }))
139
+ fastify.register(fastifyPlugin(hiDecorator, { name: 'hi' }))
140
+ fastify.register(fastifyPlugin(utilityDecorator, { dependencies: ['greet', 'hi'] }))
141
+
142
+ fastify.get('/', function (req, reply) {
143
+ // Response: {"hello":"greet message | hi message"}
144
+ reply.send({ hello: fastify.utility() })
145
+ })
146
+
147
+ fastify.listen({ port: 3000 }, (err, address) => {
148
+ if (err) throw err
149
+ })
150
+ ```
151
+
152
+ Using an arrow function breaks the binding of `this` to
153
+ the `FastifyInstance`.
154
+
155
+ If a dependency is not satisfied, the `decorate` method throws an exception.
156
+ The dependency check occurs before the server instance boots, not during
157
+ runtime.
158
+
159
+ #### `decorateReply(name, value, [dependencies])`
160
+ <a id="decorate-reply"></a>
161
+
162
+ This API adds new methods/properties to the core `Reply` object:
163
+
164
+ ```js
165
+ fastify.decorateReply('utility', function () {
166
+ // Something very useful
167
+ })
168
+ ```
169
+
170
+ Using an arrow function will break the binding of `this` to the Fastify
171
+ `Reply` instance.
172
+
173
+ Using `decorateReply` will throw and error if used with a reference type:
174
+
175
+ ```js
176
+ // Don't do this
177
+ fastify.decorateReply('foo', { bar: 'fizz'})
178
+ ```
179
+ In this example, the object reference would be shared with all requests, and
180
+ **any mutation will impact all requests, potentially creating security
181
+ vulnerabilities or memory leaks**. Fastify blocks this.
182
+
183
+ To achieve proper encapsulation across requests configure a new value for each
184
+ incoming request in the [`'onRequest'` hook](./Hooks.md#onrequest).
185
+
186
+ ```js
187
+ const fp = require('fastify-plugin')
188
+
189
+ async function myPlugin (app) {
190
+ app.decorateReply('foo')
191
+ app.addHook('onRequest', async (req, reply) => {
192
+ reply.foo = { bar: 42 }
193
+ })
194
+ }
195
+
196
+ module.exports = fp(myPlugin)
197
+ ```
198
+
199
+ See [`decorate`](#decorate) for information about the `dependencies` parameter.
200
+
201
+ #### `decorateRequest(name, value, [dependencies])`
202
+ <a id="decorate-request"></a>
203
+
204
+ As with [`decorateReply`](#decorate-reply), this API adds new methods/properties
205
+ to the core `Request` object:
206
+
207
+ ```js
208
+ fastify.decorateRequest('utility', function () {
209
+ // something very useful
210
+ })
211
+ ```
212
+
213
+ Using an arrow function will break the binding of `this` to the Fastify
214
+ `Request` instance.
215
+
216
+ Using `decorateRequest` will emit an error if used with a reference type:
217
+
218
+ ```js
219
+ // Don't do this
220
+ fastify.decorateRequest('foo', { bar: 'fizz'})
221
+ ```
222
+ In this example, the object reference would be shared with all requests, and
223
+ **any mutation will impact all requests, potentially creating security
224
+ vulnerabilities or memory leaks**. Fastify blocks this.
225
+
226
+ To achieve proper encapsulation across requests configure a new value for each
227
+ incoming request in the [`'onRequest'` hook](./Hooks.md#onrequest).
228
+
229
+ Example:
230
+
231
+ ```js
232
+ const fp = require('fastify-plugin')
233
+
234
+ async function myPlugin (app) {
235
+ app.decorateRequest('foo')
236
+ app.addHook('onRequest', async (req, reply) => {
237
+ req.foo = { bar: 42 }
238
+ })
239
+ }
240
+
241
+ module.exports = fp(myPlugin)
242
+ ```
243
+
244
+ The hook solution is more flexible and allows for more complex initialization
245
+ because more logic can be added to the `onRequest` hook.
246
+
247
+ Another approach is to use the getter/setter pattern, but it requires 2 decorators:
248
+
249
+ ```js
250
+ fastify.decorateRequest('my_decorator_holder') // define the holder
251
+ fastify.decorateRequest('user', {
252
+ getter () {
253
+ this.my_decorator_holder ??= {} // initialize the holder
254
+ return this.my_decorator_holder
255
+ }
256
+ })
257
+
258
+ fastify.get('/', async function (req, reply) {
259
+ req.user.access = 'granted'
260
+ // other code
261
+ })
262
+ ```
263
+
264
+ This ensures that the `user` property is always unique for each request.
265
+
266
+ See [`decorate`](#decorate) for information about the `dependencies` parameter.
267
+
268
+ #### `hasDecorator(name)`
269
+ <a id="has-decorator"></a>
270
+
271
+ Used to check for the existence of a server instance decoration:
272
+
273
+ ```js
274
+ fastify.hasDecorator('utility')
275
+ ```
276
+
277
+ #### hasRequestDecorator
278
+ <a id="has-request-decorator"></a>
279
+
280
+ Used to check for the existence of a Request decoration:
281
+
282
+ ```js
283
+ fastify.hasRequestDecorator('utility')
284
+ ```
285
+
286
+ #### hasReplyDecorator
287
+ <a id="has-reply-decorator"></a>
288
+
289
+ Used to check for the existence of a Reply decoration:
290
+
291
+ ```js
292
+ fastify.hasReplyDecorator('utility')
293
+ ```
294
+
295
+ ### Decorators and Encapsulation
296
+ <a id="decorators-encapsulation"></a>
297
+
298
+ Defining a decorator (using `decorate`, `decorateRequest`, or `decorateReply`)
299
+ with the same name more than once in the same **encapsulated** context will
300
+ throw an exception. For example, the following will throw:
301
+
302
+ ```js
303
+ const server = require('fastify')()
304
+
305
+ server.decorateReply('view', function (template, args) {
306
+ // Amazing view rendering engine
307
+ })
308
+
309
+ server.get('/', (req, reply) => {
310
+ reply.view('/index.html', { hello: 'world' })
311
+ })
312
+
313
+ // Somewhere else in our codebase, we define another
314
+ // view decorator. This throws.
315
+ server.decorateReply('view', function (template, args) {
316
+ // Another rendering engine
317
+ })
318
+
319
+ server.listen({ port: 3000 })
320
+ ```
321
+
322
+
323
+ But this will not:
324
+
325
+ ```js
326
+ const server = require('fastify')()
327
+
328
+ server.decorateReply('view', function (template, args) {
329
+ // Amazing view rendering engine.
330
+ })
331
+
332
+ server.register(async function (server, opts) {
333
+ // We add a view decorator to the current encapsulated
334
+ // plugin. This will not throw as outside of this encapsulated
335
+ // plugin view is the old one, while inside it is the new one.
336
+ server.decorateReply('view', function (template, args) {
337
+ // Another rendering engine
338
+ })
339
+
340
+ server.get('/', (req, reply) => {
341
+ reply.view('/index.page', { hello: 'world' })
342
+ })
343
+ }, { prefix: '/bar' })
344
+
345
+ server.listen({ port: 3000 })
346
+ ```
347
+
348
+ ### Getters and Setters
349
+ <a id="getters-setters"></a>
350
+
351
+ Decorators accept special "getter/setter" objects with `getter` and optional
352
+ `setter` functions. This allows defining properties via decorators,
353
+ for example:
354
+
355
+ ```js
356
+ fastify.decorate('foo', {
357
+ getter () {
358
+ return 'a getter'
359
+ }
360
+ })
361
+ ```
362
+
363
+ Will define the `foo` property on the Fastify instance:
364
+
365
+ ```js
366
+ console.log(fastify.foo) // 'a getter'
367
+ ```
368
+
369
+ #### `getDecorator(name)`
370
+ <a id="get-decorator"></a>
371
+
372
+ Used to retrieve an existing decorator from the Fastify instance, `Request`,
373
+ or `Reply`.
374
+ If the decorator is not defined, an `FST_ERR_DEC_UNDECLARED` error is thrown.
375
+
376
+ ```js
377
+ // Get a decorator from the Fastify instance
378
+ const utility = fastify.getDecorator('utility')
379
+
380
+ // Get a decorator from the request object
381
+ const user = request.getDecorator('user')
382
+
383
+ // Get a decorator from the reply object
384
+ const helper = reply.getDecorator('helper')
385
+ ```
386
+
387
+ The `getDecorator` method is useful for dependency validation - it can be used to
388
+ check for required decorators at registration time. If any are missing, it fails
389
+ at boot, ensuring dependencies are available during the request lifecycle.
390
+
391
+ ```js
392
+ fastify.register(async function (fastify) {
393
+ // Verify the decorator exists before using it
394
+ const usersRepository = fastify.getDecorator('usersRepository')
395
+
396
+ fastify.get('/users', async function (request, reply) {
397
+ return usersRepository.findAll()
398
+ })
399
+ })
400
+ ```
401
+
402
+ > ℹ️ Note:
403
+ > For TypeScript users, `getDecorator` supports generic type parameters.
404
+ > See the [TypeScript documentation](./TypeScript.md) for
405
+ > advanced typing examples.
406
+
407
+ #### `setDecorator(name, value)`
408
+ <a id="set-decorator"></a>
409
+
410
+ Used to safely update the value of a `Request` decorator.
411
+ If the decorator does not exist, a `FST_ERR_DEC_UNDECLARED` error is thrown.
412
+
413
+ ```js
414
+ fastify.decorateRequest('user', null)
415
+
416
+ fastify.addHook('preHandler', async (req, reply) => {
417
+ // Safely set the decorator value
418
+ req.setDecorator('user', 'Bob Dylan')
419
+ })
420
+ ```
421
+
422
+ The `setDecorator` method provides runtime safety by ensuring the decorator exists
423
+ before setting its value, preventing errors from typos in decorator names.
424
+
425
+ ```js
426
+ fastify.decorateRequest('account', null)
427
+ fastify.addHook('preHandler', async (req, reply) => {
428
+ // This will throw FST_ERR_DEC_UNDECLARED due to typo in decorator name
429
+ req.setDecorator('acount', { id: 123 })
430
+ })
431
+ ```
432
+
433
+ > ℹ️ Note:
434
+ > For TypeScript users, see the
435
+ > [TypeScript documentation](./TypeScript.md) for advanced
436
+ > typing examples using `setDecorator<T>`.
@@ -0,0 +1,194 @@
1
+ <h1 align="center">Fastify</h1>
2
+
3
+ ## Encapsulation
4
+ <a id="encapsulation"></a>
5
+
6
+ A fundamental feature of Fastify is the "encapsulation context." It governs
7
+ which [decorators](./Decorators.md), registered [hooks](./Hooks.md), and
8
+ [plugins](./Plugins.md) are available to [routes](./Routes.md). A visual
9
+ representation of the encapsulation context is shown in the following figure:
10
+
11
+ ![Figure 1](../resources/encapsulation_context.svg)
12
+
13
+ In the figure above, there are several entities:
14
+
15
+ 1. The _root context_
16
+ 2. Three _root plugins_
17
+ 3. Two _child contexts_, each with:
18
+ * Two _child plugins_
19
+ * One _grandchild context_, each with:
20
+ - Three _child plugins_
21
+
22
+ Every _child context_ and _grandchild context_ has access to the _root plugins_.
23
+ Within each _child context_, the _grandchild contexts_ have access to the
24
+ _child plugins_ registered within the containing _child context_, but the
25
+ containing _child context_ **does not** have access to the _child plugins_
26
+ registered within its _grandchild context_.
27
+
28
+ Given that everything in Fastify is a [plugin](./Plugins.md) except for the
29
+ _root context_, every "context" and "plugin" in this example is a plugin
30
+ that can consist of decorators, hooks, plugins, and routes. As plugins, they
31
+ must still signal completion either by returning a Promise (e.g., using `async`
32
+ functions) or by calling the `done` function if using the callback style.
33
+
34
+ To put this
35
+ example into concrete terms, consider a basic scenario of a REST API server
36
+ with three routes: the first route (`/one`) requires authentication, the
37
+ second route (`/two`) does not, and the third route (`/three`) has access to
38
+ the same context as the second route. Using [@fastify/bearer-auth][bearer] to
39
+ provide authentication, the code for this example is as follows:
40
+
41
+ ```js
42
+ 'use strict'
43
+
44
+ const fastify = require('fastify')()
45
+
46
+ fastify.decorateRequest('answer', 42)
47
+
48
+ fastify.register(async function authenticatedContext (childServer) {
49
+ childServer.register(require('@fastify/bearer-auth'), { keys: ['abc123'] })
50
+
51
+ childServer.route({
52
+ path: '/one',
53
+ method: 'GET',
54
+ handler (request, response) {
55
+ response.send({
56
+ answer: request.answer,
57
+ // request.foo will be undefined as it is only defined in publicContext
58
+ foo: request.foo,
59
+ // request.bar will be undefined as it is only defined in grandchildContext
60
+ bar: request.bar
61
+ })
62
+ }
63
+ })
64
+ })
65
+
66
+ fastify.register(async function publicContext (childServer) {
67
+ childServer.decorateRequest('foo', 'foo')
68
+
69
+ childServer.route({
70
+ path: '/two',
71
+ method: 'GET',
72
+ handler (request, response) {
73
+ response.send({
74
+ answer: request.answer,
75
+ foo: request.foo,
76
+ // request.bar will be undefined as it is only defined in grandchildContext
77
+ bar: request.bar
78
+ })
79
+ }
80
+ })
81
+
82
+ childServer.register(async function grandchildContext (grandchildServer) {
83
+ grandchildServer.decorateRequest('bar', 'bar')
84
+
85
+ grandchildServer.route({
86
+ path: '/three',
87
+ method: 'GET',
88
+ handler (request, response) {
89
+ response.send({
90
+ answer: request.answer,
91
+ foo: request.foo,
92
+ bar: request.bar
93
+ })
94
+ }
95
+ })
96
+ })
97
+ })
98
+
99
+ fastify.listen({ port: 8000 })
100
+ ```
101
+
102
+ The server example above demonstrates the encapsulation concepts from the
103
+ original diagram:
104
+
105
+ 1. Each _child context_ (`authenticatedContext`, `publicContext`, and
106
+ `grandchildContext`) has access to the `answer` request decorator defined in
107
+ the _root context_.
108
+ 2. Only the `authenticatedContext` has access to the `@fastify/bearer-auth`
109
+ plugin.
110
+ 3. Both the `publicContext` and `grandchildContext` have access to the `foo`
111
+ request decorator.
112
+ 4. Only the `grandchildContext` has access to the `bar` request decorator.
113
+
114
+ To see this, start the server and issue requests:
115
+
116
+ ```sh
117
+ # curl -H 'authorization: Bearer abc123' http://127.0.0.1:8000/one
118
+ {"answer":42}
119
+ # curl http://127.0.0.1:8000/two
120
+ {"answer":42,"foo":"foo"}
121
+ # curl http://127.0.0.1:8000/three
122
+ {"answer":42,"foo":"foo","bar":"bar"}
123
+ ```
124
+
125
+ [bearer]: https://github.com/fastify/fastify-bearer-auth
126
+
127
+ ## Sharing Between Contexts
128
+ <a id="shared-context"></a>
129
+
130
+ Each context in the prior example inherits _only_ from its parent contexts. Parent
131
+ contexts cannot access entities within their descendant contexts. If needed,
132
+ encapsulation can be broken using [fastify-plugin][fastify-plugin], making
133
+ anything registered in a descendant context available to the parent context.
134
+
135
+ To allow `publicContext` access to the `bar` decorator in `grandchildContext`,
136
+ rewrite the code as follows:
137
+
138
+ ```js
139
+ 'use strict'
140
+
141
+ const fastify = require('fastify')()
142
+ const fastifyPlugin = require('fastify-plugin')
143
+
144
+ fastify.decorateRequest('answer', 42)
145
+
146
+ // `authenticatedContext` omitted for clarity
147
+
148
+ fastify.register(async function publicContext (childServer) {
149
+ childServer.decorateRequest('foo', 'foo')
150
+
151
+ childServer.route({
152
+ path: '/two',
153
+ method: 'GET',
154
+ handler (request, response) {
155
+ response.send({
156
+ answer: request.answer,
157
+ foo: request.foo,
158
+ bar: request.bar
159
+ })
160
+ }
161
+ })
162
+
163
+ childServer.register(fastifyPlugin(grandchildContext))
164
+
165
+ async function grandchildContext (grandchildServer) {
166
+ grandchildServer.decorateRequest('bar', 'bar')
167
+
168
+ grandchildServer.route({
169
+ path: '/three',
170
+ method: 'GET',
171
+ handler (request, response) {
172
+ response.send({
173
+ answer: request.answer,
174
+ foo: request.foo,
175
+ bar: request.bar
176
+ })
177
+ }
178
+ })
179
+ }
180
+ })
181
+
182
+ fastify.listen({ port: 8000 })
183
+ ```
184
+
185
+ Restarting the server and re-issuing the requests for `/two` and `/three`:
186
+
187
+ ```sh
188
+ # curl http://127.0.0.1:8000/two
189
+ {"answer":42,"foo":"foo","bar":"bar"}
190
+ # curl http://127.0.0.1:8000/three
191
+ {"answer":42,"foo":"foo","bar":"bar"}
192
+ ```
193
+
194
+ [fastify-plugin]: https://github.com/fastify/fastify-plugin