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,520 @@
1
+ <h1 align="center">Fastify</h1>
2
+
3
+ # The hitchhiker's guide to plugins
4
+ First of all, `DON'T PANIC`!
5
+
6
+ Fastify was built from the beginning to be an extremely modular system. We built
7
+ a powerful API that allows you to add methods and utilities to Fastify by
8
+ creating a namespace. We built a system that creates an encapsulation model,
9
+ which allows you to split your application into multiple microservices at any
10
+ moment, without the need to refactor the entire application.
11
+
12
+ **Table of contents**
13
+ - [The hitchhiker's guide to plugins](#the-hitchhikers-guide-to-plugins)
14
+ - [Register](#register)
15
+ - [Decorators](#decorators)
16
+ - [Hooks](#hooks)
17
+ - [How to handle encapsulation and
18
+ distribution](#how-to-handle-encapsulation-and-distribution)
19
+ - [ESM support](#esm-support)
20
+ - [Handle errors](#handle-errors)
21
+ - [Custom errors](#custom-errors)
22
+ - [Emit Warnings](#emit-warnings)
23
+ - [Let's start!](#lets-start)
24
+
25
+ ## Register
26
+ <a id="register"></a>
27
+
28
+ As with JavaScript, where everything is an object, in Fastify everything is a
29
+ plugin.
30
+
31
+ Your routes, your utilities, and so on are all plugins. To add a new plugin,
32
+ whatever its functionality may be, in Fastify you have a nice and unique API:
33
+ [`register`](../Reference/Plugins.md).
34
+ ```js
35
+ fastify.register(
36
+ require('./my-plugin'),
37
+ { options }
38
+ )
39
+ ```
40
+ `register` creates a new Fastify context, which means that if you perform any
41
+ changes on the Fastify instance, those changes will not be reflected in the
42
+ context's ancestors. In other words, encapsulation!
43
+
44
+ *Why is encapsulation important?*
45
+
46
+ Well, let's say you are creating a new disruptive startup, what do you do? You
47
+ create an API server with all your stuff, everything in the same place, a
48
+ monolith!
49
+
50
+ Ok, you are growing very fast and you want to change your architecture and try
51
+ microservices. Usually, this implies a huge amount of work, because of cross
52
+ dependencies and a lack of separation of concerns in the codebase.
53
+
54
+ Fastify helps you in that regard. Thanks to the encapsulation model, it will
55
+ completely avoid cross dependencies and will help you structure your code into
56
+ cohesive blocks.
57
+
58
+ *Let's return to how to correctly use `register`.*
59
+
60
+ As you probably know, the required plugins must expose a single function with
61
+ the following signature
62
+ ```js
63
+ module.exports = function (fastify, options, done) {}
64
+ ```
65
+ Where `fastify` is the encapsulated Fastify instance, `options` is the options
66
+ object, and `done` is the function you **must** call when your plugin is ready.
67
+
68
+ Fastify's plugin model is fully reentrant and graph-based, it handles
69
+ asynchronous code without any problems and it enforces both the load and close
70
+ order of plugins. *How?* Glad you asked, check out
71
+ [`avvio`](https://github.com/mcollina/avvio)! Fastify starts loading the plugin
72
+ __after__ `.listen()`, `.inject()` or `.ready()` are called.
73
+
74
+ Inside a plugin you can do whatever you want, register routes and utilities (we
75
+ will see this in a moment), and do nested registers, just remember to call `done`
76
+ when everything is set up!
77
+ ```js
78
+ module.exports = function (fastify, options, done) {
79
+ fastify.get('/plugin', (request, reply) => {
80
+ reply.send({ hello: 'world' })
81
+ })
82
+
83
+ done()
84
+ }
85
+ ```
86
+
87
+ Well, now you know how to use the `register` API and how it works, but how do we
88
+ add new functionality to Fastify and even better, share them with other
89
+ developers?
90
+
91
+ ## Decorators
92
+ <a id="decorators"></a>
93
+
94
+ Okay, let's say that you wrote a utility that is so good that you decided to
95
+ make it available along with all your code. How would you do it? Probably
96
+ something like the following:
97
+ ```js
98
+ // your-awesome-utility.js
99
+ module.exports = function (a, b) {
100
+ return a + b
101
+ }
102
+ ```
103
+ ```js
104
+ const util = require('./your-awesome-utility')
105
+ console.log(util('that is ', 'awesome'))
106
+ ```
107
+ Now you will import your utility in every file you need it in. (And do not
108
+ forget that you will probably also need it in your tests).
109
+
110
+ Fastify offers you a more elegant and comfortable way to do this, *decorators*.
111
+ Creating a decorator is extremely easy, just use the
112
+ [`decorate`](../Reference/Decorators.md) API:
113
+ ```js
114
+ fastify.decorate('util', (a, b) => a + b)
115
+ ```
116
+ Now you can access your utility just by calling `fastify.util` whenever you need
117
+ it - even inside your test.
118
+
119
+ And here starts the magic; do you remember how just now we were talking about
120
+ encapsulation? Well, using `register` and `decorate` in conjunction enables
121
+ exactly that, let me show you an example to clarify this:
122
+ ```js
123
+ fastify.register((instance, opts, done) => {
124
+ instance.decorate('util', (a, b) => a + b)
125
+ console.log(instance.util('that is ', 'awesome'))
126
+
127
+ done()
128
+ })
129
+
130
+ fastify.register((instance, opts, done) => {
131
+ console.log(instance.util('that is ', 'awesome')) // This will throw an error
132
+
133
+ done()
134
+ })
135
+ ```
136
+ Inside the second register call `instance.util` will throw an error because
137
+ `util` exists only inside the first register context.
138
+
139
+ Let's step back for a moment and dig deeper into this: every time you use the
140
+ `register` API, a new context is created that avoids the negative situations
141
+ mentioned above.
142
+
143
+ Do note that encapsulation applies to the ancestors and siblings, but not the
144
+ children.
145
+ ```js
146
+ fastify.register((instance, opts, done) => {
147
+ instance.decorate('util', (a, b) => a + b)
148
+ console.log(instance.util('that is ', 'awesome'))
149
+
150
+ instance.register((instance, opts, done) => {
151
+ console.log(instance.util('that is ', 'awesome')) // This will not throw an error
152
+ done()
153
+ })
154
+
155
+ done()
156
+ })
157
+
158
+ fastify.register((instance, opts, done) => {
159
+ console.log(instance.util('that is ', 'awesome')) // This will throw an error
160
+
161
+ done()
162
+ })
163
+ ```
164
+ *Take home message: if you need a utility that is available in every part of
165
+ your application, take care that it is declared in the root scope of your
166
+ application. If that is not an option, you can use the `fastify-plugin` utility
167
+ as described [here](#distribution).*
168
+
169
+ `decorate` is not the only API that you can use to extend the server
170
+ functionality, you can also use `decorateRequest` and `decorateReply`.
171
+
172
+ *`decorateRequest` and `decorateReply`? Why do we need them if we already have
173
+ `decorate`?*
174
+
175
+ Good question, we added them to make Fastify more developer-friendly. Let's see
176
+ an example:
177
+ ```js
178
+ fastify.decorate('html', payload => {
179
+ return generateHtml(payload)
180
+ })
181
+
182
+ fastify.get('/html', (request, reply) => {
183
+ reply
184
+ .type('text/html')
185
+ .send(fastify.html({ hello: 'world' }))
186
+ })
187
+ ```
188
+ It works, but it could be much better!
189
+ ```js
190
+ fastify.decorateReply('html', function (payload) {
191
+ this.type('text/html') // This is the 'Reply' object
192
+ this.send(generateHtml(payload))
193
+ })
194
+
195
+ fastify.get('/html', (request, reply) => {
196
+ reply.html({ hello: 'world' })
197
+ })
198
+ ```
199
+ Reminder that the `this` keyword is not available on *arrow functions*,
200
+ so when passing functions in *`decorateReply`* and *`decorateRequest`* as
201
+ a utility that also needs access to the `request` and `reply` instance,
202
+ a function that is defined using the `function` keyword is needed instead
203
+ of an *arrow function expression*.
204
+
205
+ You can do the same for the `request` object:
206
+ ```js
207
+ fastify.decorate('getBoolHeader', (req, name) => {
208
+ return req.headers[name] ?? false // We return `false` if header is missing
209
+ })
210
+
211
+ fastify.addHook('preHandler', (request, reply, done) => {
212
+ request.isHappy = fastify.getBoolHeader(request, 'happy')
213
+ done()
214
+ })
215
+
216
+ fastify.get('/happiness', (request, reply) => {
217
+ reply.send({ happy: request.isHappy })
218
+ })
219
+ ```
220
+ Again, it works, but it can be much better!
221
+ ```js
222
+ fastify.decorateRequest('setBoolHeader', function (name) {
223
+ this.isHappy = this.headers[name] ?? false
224
+ })
225
+
226
+ fastify.decorateRequest('isHappy', false) // This will be added to the Request object prototype, yay speed!
227
+
228
+ fastify.addHook('preHandler', (request, reply, done) => {
229
+ request.setBoolHeader('happy')
230
+ done()
231
+ })
232
+
233
+ fastify.get('/happiness', (request, reply) => {
234
+ reply.send({ happy: request.isHappy })
235
+ })
236
+ ```
237
+
238
+ We have seen how to extend server functionality and how to handle the
239
+ encapsulation system, but what if you need to add a function that must be
240
+ executed whenever the server "[emits](../Reference/Lifecycle.md)" an
241
+ event?
242
+
243
+ ## Hooks
244
+ <a id="hooks"></a>
245
+
246
+ You just built an amazing utility, but now you need to execute that for every
247
+ request, this is what you will likely do:
248
+ ```js
249
+ fastify.decorate('util', (request, key, value) => { request[key] = value })
250
+
251
+ fastify.get('/plugin1', (request, reply) => {
252
+ fastify.util(request, 'timestamp', new Date())
253
+ reply.send(request)
254
+ })
255
+
256
+ fastify.get('/plugin2', (request, reply) => {
257
+ fastify.util(request, 'timestamp', new Date())
258
+ reply.send(request)
259
+ })
260
+ ```
261
+ I think we all agree that this is terrible. Repeated code, awful readability and
262
+ it cannot scale.
263
+
264
+ So what can you do to avoid this annoying issue? Yes, you are right, use a
265
+ [hook](../Reference/Hooks.md)!
266
+
267
+ ```js
268
+ fastify.decorate('util', (request, key, value) => { request[key] = value })
269
+
270
+ fastify.addHook('preHandler', (request, reply, done) => {
271
+ fastify.util(request, 'timestamp', new Date())
272
+ done()
273
+ })
274
+
275
+ fastify.get('/plugin1', (request, reply) => {
276
+ reply.send(request)
277
+ })
278
+
279
+ fastify.get('/plugin2', (request, reply) => {
280
+ reply.send(request)
281
+ })
282
+ ```
283
+ Now for every request, you will run your utility. You can register as many hooks
284
+ as you need.
285
+
286
+ Sometimes you want a hook that should be executed for just a subset of routes,
287
+ how can you do that? Yep, encapsulation!
288
+
289
+ ```js
290
+ fastify.register((instance, opts, done) => {
291
+ instance.decorate('util', (request, key, value) => { request[key] = value })
292
+
293
+ instance.addHook('preHandler', (request, reply, done) => {
294
+ instance.util(request, 'timestamp', new Date())
295
+ done()
296
+ })
297
+
298
+ instance.get('/plugin1', (request, reply) => {
299
+ reply.send(request)
300
+ })
301
+
302
+ done()
303
+ })
304
+
305
+ fastify.get('/plugin2', (request, reply) => {
306
+ reply.send(request)
307
+ })
308
+ ```
309
+ Now your hook will run just for the first route!
310
+
311
+ An alternative approach is to make use of the [onRoute hook](../Reference/Hooks.md#onroute)
312
+ to customize application routes dynamically from inside the plugin. Every time
313
+ a new route is registered, you can read and modify the route options. For example,
314
+ based on a [route config option](../Reference/Routes.md#routes-options):
315
+
316
+ ```js
317
+ fastify.register((instance, opts, done) => {
318
+ instance.decorate('util', (request, key, value) => { request[key] = value })
319
+
320
+ function handler(request, reply, done) {
321
+ instance.util(request, 'timestamp', new Date())
322
+ done()
323
+ }
324
+
325
+ instance.addHook('onRoute', (routeOptions) => {
326
+ if (routeOptions.config && routeOptions.config.useUtil === true) {
327
+ // set or add our handler to the route preHandler hook
328
+ if (!routeOptions.preHandler) {
329
+ routeOptions.preHandler = [handler]
330
+ return
331
+ }
332
+ if (Array.isArray(routeOptions.preHandler)) {
333
+ routeOptions.preHandler.push(handler)
334
+ return
335
+ }
336
+ routeOptions.preHandler = [routeOptions.preHandler, handler]
337
+ }
338
+ })
339
+
340
+ instance.get('/plugin1', {config: {useUtil: true}}, (request, reply) => {
341
+ reply.send(request)
342
+ })
343
+
344
+ instance.get('/plugin2', (request, reply) => {
345
+ reply.send(request)
346
+ })
347
+
348
+ done()
349
+ })
350
+ ```
351
+
352
+ This variant becomes extremely useful if you plan to distribute your plugin, as
353
+ described in the next section.
354
+
355
+ As you probably noticed by now, `request` and `reply` are not the standard
356
+ Node.js *request* and *response* objects, but Fastify's objects.
357
+
358
+
359
+ ## How to handle encapsulation and distribution
360
+ <a id="distribution"></a>
361
+
362
+ Perfect, now you know (almost) all of the tools that you can use to extend
363
+ Fastify. Nevertheless, chances are that you came across one big issue: how is
364
+ distribution handled?
365
+
366
+ The preferred way to distribute a utility is to wrap all your code inside a
367
+ `register`. Using this, your plugin can support asynchronous bootstrapping
368
+ *(since `decorate` is a synchronous API)*, in the case of a database connection
369
+ for example.
370
+
371
+ *Wait, what? Didn't you tell me that `register` creates an encapsulation and
372
+ that the stuff I create inside will not be available outside?*
373
+
374
+ Yes, I said that. However, what I didn't tell you is that you can tell Fastify
375
+ to avoid this behavior with the
376
+ [`fastify-plugin`](https://github.com/fastify/fastify-plugin) module.
377
+ ```js
378
+ const fp = require('fastify-plugin')
379
+ const dbClient = require('db-client')
380
+
381
+ function dbPlugin (fastify, opts, done) {
382
+ dbClient.connect(opts.url, (err, conn) => {
383
+ fastify.decorate('db', conn)
384
+ done()
385
+ })
386
+ }
387
+
388
+ module.exports = fp(dbPlugin)
389
+ ```
390
+ You can also tell `fastify-plugin` to check the installed version of Fastify, in
391
+ case you need a specific API.
392
+
393
+ As we mentioned earlier, Fastify starts loading its plugins __after__
394
+ `.listen()`, `.inject()` or `.ready()` are called and as such, __after__ they
395
+ have been declared. This means that, even though the plugin may inject variables
396
+ to the external Fastify instance via [`decorate`](../Reference/Decorators.md),
397
+ the decorated variables will not be accessible before calling `.listen()`,
398
+ `.inject()`, or `.ready()`.
399
+
400
+ In case you rely on a variable injected by a preceding plugin and want to pass
401
+ that in the `options` argument of `register`, you can do so by using a function
402
+ instead of an object:
403
+ ```js
404
+ const fastify = require('fastify')()
405
+ const fp = require('fastify-plugin')
406
+ const dbClient = require('db-client')
407
+
408
+ function dbPlugin (fastify, opts, done) {
409
+ dbClient.connect(opts.url, (err, conn) => {
410
+ fastify.decorate('db', conn)
411
+ done()
412
+ })
413
+ }
414
+
415
+ fastify.register(fp(dbPlugin), { url: 'https://fastify.example' })
416
+ fastify.register(require('your-plugin'), parent => {
417
+ return { connection: parent.db, otherOption: 'foo-bar' }
418
+ })
419
+ ```
420
+ In the above example, the `parent` variable of the function passed in as the
421
+ second argument of `register` is a copy of the **external Fastify instance**
422
+ that the plugin was registered at. This means that we can access any
423
+ variables that were injected by preceding plugins in the order of declaration.
424
+
425
+ ## ESM support
426
+ <a id="esm-support"></a>
427
+
428
+ ESM is supported as well from [Node.js
429
+ `v13.3.0`](https://nodejs.org/api/esm.html) and above! Just export your plugin
430
+ as an ESM module and you are good to go!
431
+
432
+ ```js
433
+ // plugin.mjs
434
+ async function plugin (fastify, opts) {
435
+ fastify.get('/', async (req, reply) => {
436
+ return { hello: 'world' }
437
+ })
438
+ }
439
+
440
+ export default plugin
441
+ ```
442
+
443
+ ## Handle errors
444
+ <a id="handle-errors"></a>
445
+
446
+ One of your plugins may fail during startup. Maybe you expect it
447
+ and you have a custom logic that will be triggered in that case. How can you
448
+ implement this? The `after` API is what you need. `after` simply registers a
449
+ callback that will be executed just after a register, and it can take up to
450
+ three parameters.
451
+
452
+ The callback changes based on the parameters you are giving:
453
+
454
+ 1. If no parameter is given to the callback and there is an error, that error
455
+ will be passed to the next error handler.
456
+ 1. If one parameter is given to the callback, that parameter will be the error
457
+ object.
458
+ 1. If two parameters are given to the callback, the first will be the error
459
+ object; the second will be the done callback.
460
+ 1. If three parameters are given to the callback, the first will be the error
461
+ object, the second will be the top-level context unless you have specified
462
+ both server and override, in that case, the context will be what the override
463
+ returns, and the third the done callback.
464
+
465
+ Let's see how to use it:
466
+ ```js
467
+ fastify
468
+ .register(require('./database-connector'))
469
+ .after(err => {
470
+ if (err) throw err
471
+ })
472
+ ```
473
+
474
+ ## Custom errors
475
+ <a id="custom-errors"></a>
476
+
477
+ If your plugin needs to expose custom errors, you can easily generate consistent
478
+ error objects across your codebase and plugins with the
479
+ [`@fastify/error`](https://github.com/fastify/fastify-error) module.
480
+
481
+ ```js
482
+ const createError = require('@fastify/error')
483
+ const CustomError = createError('ERROR_CODE', 'message')
484
+ console.log(new CustomError())
485
+ ```
486
+
487
+ ## Emit Warnings
488
+ <a id="emit-warnings"></a>
489
+
490
+ If you want to deprecate an API, or you want to warn the user about a specific
491
+ use case, you can use the
492
+ [`process-warning`](https://github.com/fastify/process-warning) module.
493
+
494
+ ```js
495
+ const warning = require('process-warning')()
496
+ warning.create('MyPluginWarning', 'MP_ERROR_CODE', 'message')
497
+ warning.emit('MP_ERROR_CODE')
498
+ ```
499
+
500
+ ## Let's start!
501
+ <a id="start"></a>
502
+
503
+ Awesome, now you know everything you need to know about Fastify and its plugin
504
+ system to start building your first plugin, and please if you do, tell us! We
505
+ will add it to the [*ecosystem*](https://github.com/fastify/fastify#ecosystem)
506
+ section of our documentation!
507
+
508
+ If you want to see some real-world examples, check out:
509
+ - [`@fastify/view`](https://github.com/fastify/point-of-view) Templates
510
+ rendering (*ejs, pug, handlebars, marko*) plugin support for Fastify.
511
+ - [`@fastify/mongodb`](https://github.com/fastify/fastify-mongodb) Fastify
512
+ MongoDB connection plugin, with this you can share the same MongoDB connection
513
+ pool in every part of your server.
514
+ - [`@fastify/multipart`](https://github.com/fastify/fastify-multipart) Multipart
515
+ support for Fastify
516
+ - [`@fastify/helmet`](https://github.com/fastify/fastify-helmet) Important
517
+ security headers for Fastify
518
+
519
+
520
+ *Do you feel like something is missing here? Let us know! :)*