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,1130 @@
1
+ <h1 align="center">Fastify</h1>
2
+
3
+ ## Validation and Serialization
4
+ Fastify uses a schema-based approach. We recommend using
5
+ [JSON Schema](https://json-schema.org/) to validate routes and serialize outputs.
6
+ Fastify compiles the schema into a highly performant function.
7
+
8
+ Validation is only attempted if the content type is `application/json`,
9
+ unless the body schema uses the [`content`](#body-content-type-validation)
10
+ property to specify validation per content type. When the body schema defines
11
+ a `content` field, it must enumerate all possible content types the
12
+ application expects to handle with the associated handler.
13
+
14
+ All examples use the
15
+ [JSON Schema Draft 7](https://json-schema.org/draft-07)
16
+ specification.
17
+
18
+ > ⚠ Warning:
19
+ > Treat schema definitions as application code. Validation and serialization
20
+ > features use `new Function()`, which is unsafe with user-provided schemas. See
21
+ > [Ajv](https://www.npmjs.com/package/ajv) and
22
+ > [fast-json-stringify](https://www.npmjs.com/package/fast-json-stringify) for details.
23
+ >
24
+ > Whilst Fastify supports the
25
+ > [`$async` Ajv feature](https://ajv.js.org/guide/async-validation.html),
26
+ > it should not be used for initial validation. Accessing databases during
27
+ > validation may lead to Denial of Service attacks. Use
28
+ > [Fastify's hooks](./Hooks.md) like `preHandler` for `async` tasks after validation.
29
+ >
30
+ > When using custom validators with async `preValidation` hooks,
31
+ > validators **must return** `{error}` objects instead of throwing errors.
32
+ > Throwing errors from custom validators will cause unhandled promise rejections
33
+ > that crash the application when combined with async hooks. See the
34
+ > [custom validator examples](#using-other-validation-libraries) below for the
35
+ > correct pattern.
36
+
37
+ ### Core concepts
38
+ Validation and serialization are handled by two customizable dependencies:
39
+ - [Ajv v8](https://www.npmjs.com/package/ajv) for request validation
40
+ - [fast-json-stringify](https://www.npmjs.com/package/fast-json-stringify) for
41
+ response body serialization
42
+
43
+ These dependencies share only the JSON schemas added to Fastify's instance via
44
+ `.addSchema(schema)`.
45
+
46
+ #### Adding a shared schema
47
+ <a id="shared-schema"></a>
48
+
49
+ The `addSchema` API allows adding multiple schemas to the Fastify instance for
50
+ reuse throughout the application. This API is encapsulated.
51
+
52
+ Shared schemas can be reused with the JSON Schema
53
+ [**`$ref`**](https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-01#section-8)
54
+ keyword. Here is an overview of how references work:
55
+
56
+ + `myField: { $ref: '#foo' }` searches for `$id: '#foo'` in the current schema
57
+ + `myField: { $ref: '#/definitions/foo' }` searches for `definitions.foo` in the
58
+ current schema
59
+ + `myField: { $ref: 'http://url.com/sh.json#' }` searches for a shared schema
60
+ with `$id: 'http://url.com/sh.json'`
61
+ + `myField: { $ref: 'http://url.com/sh.json#/definitions/foo' }` searches for a
62
+ shared schema with `$id: 'http://url.com/sh.json'` and uses `definitions.foo`
63
+ + `myField: { $ref: 'http://url.com/sh.json#foo' }` searches for a shared schema
64
+ with `$id: 'http://url.com/sh.json'` and looks for `$id: '#foo'` within it
65
+
66
+ **Simple usage:**
67
+
68
+ ```js
69
+ fastify.addSchema({
70
+ $id: 'http://fastify.example/',
71
+ type: 'object',
72
+ properties: {
73
+ hello: { type: 'string' }
74
+ }
75
+ })
76
+
77
+ fastify.post('/', {
78
+ handler () {},
79
+ schema: {
80
+ body: {
81
+ type: 'array',
82
+ items: { $ref: 'http://fastify.example#/properties/hello' }
83
+ }
84
+ }
85
+ })
86
+ ```
87
+
88
+ **`$ref` as root reference:**
89
+
90
+ ```js
91
+ fastify.addSchema({
92
+ $id: 'commonSchema',
93
+ type: 'object',
94
+ properties: {
95
+ hello: { type: 'string' }
96
+ }
97
+ })
98
+
99
+ fastify.post('/', {
100
+ handler () {},
101
+ schema: {
102
+ body: { $ref: 'commonSchema#' },
103
+ headers: { $ref: 'commonSchema#' }
104
+ }
105
+ })
106
+ ```
107
+
108
+ #### Retrieving the shared schemas
109
+ <a id="get-shared-schema"></a>
110
+
111
+ If the validator and serializer are customized, `.addSchema` is not useful since
112
+ Fastify no longer controls them. To access schemas added to the Fastify instance,
113
+ use `.getSchemas()`:
114
+
115
+ ```js
116
+ fastify.addSchema({
117
+ $id: 'schemaId',
118
+ type: 'object',
119
+ properties: {
120
+ hello: { type: 'string' }
121
+ }
122
+ })
123
+
124
+ const mySchemas = fastify.getSchemas()
125
+ const mySchema = fastify.getSchema('schemaId')
126
+ ```
127
+
128
+ The `getSchemas` function is encapsulated and returns shared schemas available
129
+ in the selected scope:
130
+
131
+ ```js
132
+ fastify.addSchema({ $id: 'one', my: 'hello' })
133
+ // will return only `one` schema
134
+ fastify.get('/', (request, reply) => { reply.send(fastify.getSchemas()) })
135
+
136
+ fastify.register((instance, opts, done) => {
137
+ instance.addSchema({ $id: 'two', my: 'ciao' })
138
+ // will return `one` and `two` schemas
139
+ instance.get('/sub', (request, reply) => { reply.send(instance.getSchemas()) })
140
+
141
+ instance.register((subinstance, opts, done) => {
142
+ subinstance.addSchema({ $id: 'three', my: 'hola' })
143
+ // will return `one`, `two` and `three`
144
+ subinstance.get('/deep', (request, reply) => { reply.send(subinstance.getSchemas()) })
145
+ done()
146
+ })
147
+ done()
148
+ })
149
+ ```
150
+
151
+
152
+ ### Validation
153
+ Route validation relies on [Ajv v8](https://www.npmjs.com/package/ajv), a
154
+ high-performance JSON Schema validator. To validate input, add the required
155
+ fields to the route schema.
156
+
157
+ Supported validations include:
158
+ - `body`: validates the request body for POST, PUT, or PATCH methods.
159
+ - `querystring` or `query`: validates the query string.
160
+ - `params`: validates the route parameters.
161
+ - `headers`: validates the request headers.
162
+
163
+ Validations can be a complete JSON Schema object with a `type` of `'object'` and
164
+ a `'properties'` object containing parameters, or a simpler variation listing
165
+ parameters at the top level.
166
+
167
+ > ℹ For using the latest Ajv (v8), refer to the
168
+ > [`schemaController`](./Server.md#schema-controller) section.
169
+
170
+ Example:
171
+ ```js
172
+ const bodyJsonSchema = {
173
+ type: 'object',
174
+ required: ['requiredKey'],
175
+ properties: {
176
+ someKey: { type: 'string' },
177
+ someOtherKey: { type: 'number' },
178
+ requiredKey: {
179
+ type: 'array',
180
+ maxItems: 3,
181
+ items: { type: 'integer' }
182
+ },
183
+ nullableKey: { type: ['number', 'null'] }, // or { type: 'number', nullable: true }
184
+ multipleTypesKey: { type: ['boolean', 'number'] },
185
+ multipleRestrictedTypesKey: {
186
+ oneOf: [
187
+ { type: 'string', maxLength: 5 },
188
+ { type: 'number', minimum: 10 }
189
+ ]
190
+ },
191
+ enumKey: {
192
+ type: 'string',
193
+ enum: ['John', 'Foo']
194
+ },
195
+ notTypeKey: {
196
+ not: { type: 'array' }
197
+ }
198
+ }
199
+ }
200
+
201
+ const queryStringJsonSchema = {
202
+ type: 'object',
203
+ properties: {
204
+ name: { type: 'string' },
205
+ excitement: { type: 'integer' }
206
+ }
207
+ }
208
+
209
+ const paramsJsonSchema = {
210
+ type: 'object',
211
+ properties: {
212
+ par1: { type: 'string' },
213
+ par2: { type: 'number' }
214
+ }
215
+ }
216
+
217
+ const headersJsonSchema = {
218
+ type: 'object',
219
+ properties: {
220
+ 'x-foo': { type: 'string' }
221
+ },
222
+ required: ['x-foo']
223
+ }
224
+
225
+ const schema = {
226
+ body: bodyJsonSchema,
227
+ querystring: queryStringJsonSchema,
228
+ params: paramsJsonSchema,
229
+ headers: headersJsonSchema
230
+ }
231
+
232
+ fastify.post('/the/url', { schema }, handler)
233
+ ```
234
+
235
+ #### Body Content-Type Validation
236
+ <a id="body-content-type-validation"></a>
237
+
238
+ For `body` schema, it is further possible to differentiate the schema per content
239
+ type by nesting the schemas inside `content` property. The schema validation
240
+ will be applied based on the `Content-Type` header in the request.
241
+
242
+ ```js
243
+ fastify.post('/the/url', {
244
+ schema: {
245
+ body: {
246
+ content: {
247
+ 'application/json': {
248
+ schema: { type: 'object' }
249
+ },
250
+ 'text/plain': {
251
+ schema: { type: 'string' }
252
+ }
253
+ // Other content types will not be validated
254
+ }
255
+ }
256
+ }
257
+ }, handler)
258
+ ```
259
+
260
+ > ⚠ Warning:
261
+ > When using [custom content type parsers](./ContentTypeParser.md), the parsed
262
+ > body is validated **only** when the request content type matches a key in the
263
+ > schema `content` map.
264
+ >
265
+ > Schema selection uses an exact match on the request's
266
+ > [essence MIME type](https://mimesniff.spec.whatwg.org/#mime-type-miscellaneous)
267
+ > (for example, `application/json`). If a parser is registered with a regular
268
+ > expression (for example, `/^application\/.*json$/`), the parser can accept
269
+ > more content types than the `content` map covers. Requests in that gap are
270
+ > parsed but **not validated**.
271
+ >
272
+ > Ensure every content type accepted by the parser has a corresponding key in
273
+ > the `content` map, or use a catch-all body schema without `content` when
274
+ > strict per-content-type discrimination is not required.
275
+ >
276
+ > ```js
277
+ > // Add a custom parser for YAML
278
+ > fastify.addContentTypeParser('application/yaml', { parseAs: 'string' }, (req, body, done) => {
279
+ > done(null, YAML.parse(body))
280
+ > })
281
+ >
282
+ > fastify.post('/the/url', {
283
+ > schema: {
284
+ > body: {
285
+ > content: {
286
+ > 'application/json': {
287
+ > schema: { type: 'object', properties: { name: { type: 'string' } }, required: ['name'] }
288
+ > },
289
+ > // Without this entry, application/yaml requests will NOT be validated
290
+ > 'application/yaml': {
291
+ > schema: { type: 'object', properties: { name: { type: 'string' } }, required: ['name'] }
292
+ > }
293
+ > }
294
+ > }
295
+ > }
296
+ > }, handler)
297
+ > ```
298
+
299
+ Note that Ajv will try to [coerce](https://ajv.js.org/coercion.html) values to
300
+ the types specified in the schema `type` keywords, both to pass validation and
301
+ to use the correctly typed data afterwards.
302
+
303
+ The Ajv default configuration in Fastify supports coercing array parameters in
304
+ `querystring`. Example:
305
+
306
+ ```js
307
+ const opts = {
308
+ schema: {
309
+ querystring: {
310
+ type: 'object',
311
+ properties: {
312
+ ids: {
313
+ type: 'array',
314
+ default: []
315
+ },
316
+ },
317
+ }
318
+ }
319
+ }
320
+
321
+ fastify.get('/', opts, (request, reply) => {
322
+ reply.send({ params: request.query }) // echo the querystring
323
+ })
324
+
325
+ fastify.listen({ port: 3000 }, (err) => {
326
+ if (err) throw err
327
+ })
328
+ ```
329
+
330
+ ```sh
331
+ curl -X GET "http://localhost:3000/?ids=1
332
+
333
+ {"params":{"ids":["1"]}}
334
+ ```
335
+
336
+ A custom schema validator can be specified for each parameter type (body,
337
+ querystring, params, headers).
338
+
339
+ For example, the following code disables type coercion only for the `body`
340
+ parameters, changing the Ajv default options:
341
+
342
+ ```js
343
+ const schemaCompilers = {
344
+ body: new Ajv({
345
+ removeAdditional: false,
346
+ coerceTypes: false,
347
+ allErrors: true
348
+ }),
349
+ params: new Ajv({
350
+ removeAdditional: false,
351
+ coerceTypes: true,
352
+ allErrors: true
353
+ }),
354
+ querystring: new Ajv({
355
+ removeAdditional: false,
356
+ coerceTypes: true,
357
+ allErrors: true
358
+ }),
359
+ headers: new Ajv({
360
+ removeAdditional: false,
361
+ coerceTypes: true,
362
+ allErrors: true
363
+ })
364
+ }
365
+
366
+ server.setValidatorCompiler(req => {
367
+ if (!req.httpPart) {
368
+ throw new Error('Missing httpPart')
369
+ }
370
+ const compiler = schemaCompilers[req.httpPart]
371
+ if (!compiler) {
372
+ throw new Error(`Missing compiler for ${req.httpPart}`)
373
+ }
374
+ return compiler.compile(req.schema)
375
+ })
376
+ ```
377
+
378
+ When type coercion is enabled, using `anyOf` with nullable primitive types
379
+ can produce unexpected results. For example, a value of `0` or `false` may be
380
+ coerced to `null` because Ajv evaluates `anyOf` schemas in order and applies
381
+ type coercion during matching. This means the `{ "type": "null" }` branch can
382
+ match before the intended type:
383
+
384
+ ```json
385
+ {
386
+ "anyOf": [
387
+ { "type": "null" },
388
+ { "type": "number" }
389
+ ]
390
+ }
391
+ ```
392
+
393
+ To avoid this, use the `nullable` keyword instead of `anyOf` for primitive
394
+ types:
395
+
396
+ ```json
397
+ {
398
+ "type": "number",
399
+ "nullable": true
400
+ }
401
+ ```
402
+
403
+ For more information, see [Ajv Coercion](https://ajv.js.org/coercion.html).
404
+
405
+ #### Ajv Plugins
406
+ <a id="ajv-plugins"></a>
407
+
408
+ A list of plugins can be provided for use with the default `ajv` instance.
409
+ Ensure the plugin is **compatible with the Ajv version shipped within Fastify**.
410
+
411
+ > Refer to [`ajv options`](./Server.md#ajv) to check plugins format.
412
+
413
+ ```js
414
+ const fastify = require('fastify')({
415
+ ajv: {
416
+ plugins: [
417
+ require('ajv-merge-patch')
418
+ ]
419
+ }
420
+ })
421
+
422
+ fastify.post('/', {
423
+ handler (req, reply) { reply.send({ ok: 1 }) },
424
+ schema: {
425
+ body: {
426
+ $patch: {
427
+ source: {
428
+ type: 'object',
429
+ properties: {
430
+ q: {
431
+ type: 'string'
432
+ }
433
+ }
434
+ },
435
+ with: [
436
+ {
437
+ op: 'add',
438
+ path: '/properties/q',
439
+ value: { type: 'number' }
440
+ }
441
+ ]
442
+ }
443
+ }
444
+ }
445
+ })
446
+
447
+ fastify.post('/foo', {
448
+ handler (req, reply) { reply.send({ ok: 1 }) },
449
+ schema: {
450
+ body: {
451
+ $merge: {
452
+ source: {
453
+ type: 'object',
454
+ properties: {
455
+ q: {
456
+ type: 'string'
457
+ }
458
+ }
459
+ },
460
+ with: {
461
+ required: ['q']
462
+ }
463
+ }
464
+ }
465
+ }
466
+ })
467
+ ```
468
+
469
+ #### Validator Compiler
470
+ <a id="schema-validator"></a>
471
+
472
+ The `validatorCompiler` is a function that returns a function to validate the
473
+ body, URL parameters, headers, and query string. The default `validatorCompiler`
474
+ returns a function that implements the [ajv](https://ajv.js.org/) validation
475
+ interface. Fastify uses it internally to speed up validation.
476
+
477
+ Fastify's [baseline ajv
478
+ configuration](https://github.com/fastify/ajv-compiler#ajv-configuration) is:
479
+
480
+ ```js
481
+ {
482
+ coerceTypes: 'array', // change data type of data to match type keyword
483
+ useDefaults: true, // replace missing properties and items with the values from corresponding default keyword
484
+ removeAdditional: true, // remove additional properties if additionalProperties is set to false, see: https://ajv.js.org/guide/modifying-data.html#removing-additional-properties
485
+ uriResolver: require('fast-uri'),
486
+ addUsedSchema: false,
487
+ // Explicitly set allErrors to `false`.
488
+ // When set to `true`, a DoS attack is possible.
489
+ allErrors: false
490
+ }
491
+ ```
492
+
493
+ Modify the baseline configuration by providing
494
+ [`ajv.customOptions`](./Server.md#factory-ajv) to the Fastify factory.
495
+
496
+ To change or set additional config options, create a custom instance and
497
+ override the existing one:
498
+
499
+ ```js
500
+ const fastify = require('fastify')()
501
+ const Ajv = require('ajv')
502
+ const ajv = new Ajv({
503
+ removeAdditional: 'all',
504
+ useDefaults: true,
505
+ coerceTypes: 'array',
506
+ // any other options
507
+ // ...
508
+ })
509
+ fastify.setValidatorCompiler(({ schema, method, url, httpPart }) => {
510
+ return ajv.compile(schema)
511
+ })
512
+ ```
513
+
514
+ > ℹ️ Note:
515
+ > When using a custom validator instance, add schemas to the validator
516
+ > instead of Fastify. Fastify's `addSchema` method will not recognize the custom
517
+ > validator.
518
+
519
+ ##### Using other validation libraries
520
+ <a id="using-other-validation-libraries"></a>
521
+
522
+ The `setValidatorCompiler` function allows substituting `ajv` with other
523
+ JavaScript validation libraries like [joi](https://github.com/hapijs/joi/) or
524
+ [yup](https://github.com/jquense/yup/), or a custom one:
525
+
526
+ ```js
527
+ const Joi = require('joi')
528
+
529
+ fastify.setValidatorCompiler(({ schema }) => {
530
+ return (data) => {
531
+ try {
532
+ const { error, value } = schema.validate(data)
533
+ if (error) {
534
+ return { error } // Return the error, do not throw it
535
+ }
536
+ return { value }
537
+ } catch (e) {
538
+ return { error: e } // Catch any unexpected errors too
539
+ }
540
+ }
541
+ })
542
+
543
+ fastify.post('/the/url', {
544
+ schema: {
545
+ body: Joi.object().keys({
546
+ hello: Joi.string().required()
547
+ }).required()
548
+ }
549
+ }, handler)
550
+ ```
551
+
552
+ ```js
553
+ const yup = require('yup')
554
+ // Validation options to match ajv's baseline options used in Fastify
555
+ const yupOptions = {
556
+ strict: false,
557
+ abortEarly: false, // return all errors
558
+ stripUnknown: true, // remove additional properties
559
+ recursive: true
560
+ }
561
+
562
+ fastify.post('/the/url', {
563
+ schema: {
564
+ body: yup.object({
565
+ age: yup.number().integer().required(),
566
+ sub: yup.object().shape({
567
+ name: yup.string().required()
568
+ }).required()
569
+ })
570
+ },
571
+ validatorCompiler: ({ schema, method, url, httpPart }) => {
572
+ return function (data) {
573
+ // with option strict = false, yup `validateSync` function returns the
574
+ // coerced value if validation was successful, or throws if validation failed
575
+ try {
576
+ const result = schema.validateSync(data, yupOptions)
577
+ return { value: result }
578
+ } catch (e) {
579
+ return { error: e }
580
+ }
581
+ }
582
+ }
583
+ }, handler)
584
+ ```
585
+
586
+ ##### Custom Validator Best Practices
587
+
588
+ When implementing custom validators, follow these patterns to ensure compatibility
589
+ with all Fastify features:
590
+
591
+ **Always return objects, never throw:**
592
+ ```js
593
+ return { value: validatedData } // On success
594
+ return { error: validationError } // On failure
595
+ ```
596
+
597
+ **Use try-catch for safety:**
598
+ ```js
599
+ fastify.setValidatorCompiler(({ schema }) => {
600
+ return (data) => {
601
+ try {
602
+ // Validation logic here
603
+ const result = schema.validate(data)
604
+ if (result.error) {
605
+ return { error: result.error }
606
+ }
607
+ return { value: result.value }
608
+ } catch (e) {
609
+ // Catch any unexpected errors
610
+ return { error: e }
611
+ }
612
+ }
613
+ })
614
+ ```
615
+
616
+ This pattern ensures validators work correctly with both sync and async
617
+ `preValidation` hooks, preventing unhandled promise rejections that can crash
618
+ an application.
619
+
620
+ ##### .statusCode property
621
+
622
+ All validation errors have a `.statusCode` property set to `400`, ensuring the
623
+ default error handler sets the response status code to `400`.
624
+
625
+ ```js
626
+ fastify.setErrorHandler(function (error, request, reply) {
627
+ request.log.error(error, `This error has status code ${error.statusCode}`)
628
+ reply.status(error.statusCode).send(error)
629
+ })
630
+ ```
631
+
632
+ ##### Validation messages with other validation libraries
633
+
634
+ Fastify's validation error messages are tightly coupled to the default
635
+ validation engine: errors returned from `ajv` are eventually run through the
636
+ `schemaErrorFormatter` function which builds human-friendly error messages.
637
+ However, the `schemaErrorFormatter` function is written with `ajv` in mind.
638
+ This may result in odd or incomplete error messages when using other validation
639
+ libraries.
640
+
641
+ To circumvent this issue, there are two main options:
642
+
643
+ 1. Ensure the validation function (returned by the custom `schemaCompiler`)
644
+ returns errors in the same structure and format as `ajv`.
645
+ 2. Use a custom `errorHandler` to intercept and format custom validation errors.
646
+
647
+ Fastify adds two properties to all validation errors to help write a custom
648
+ `errorHandler`:
649
+
650
+ * `validation`: the content of the `error` property of the object returned by
651
+ the validation function (returned by the custom `schemaCompiler`)
652
+ * `validationContext`: the context (body, params, query, headers) where the
653
+ validation error occurred
654
+
655
+ A contrived example of such a custom `errorHandler` handling validation errors
656
+ is shown below:
657
+
658
+ ```js
659
+ const errorHandler = (error, request, reply) => {
660
+ const statusCode = error.statusCode
661
+ let response
662
+
663
+ const { validation, validationContext } = error
664
+
665
+ // check if we have a validation error
666
+ if (validation) {
667
+ response = {
668
+ // validationContext will be 'body', 'params', 'headers', or 'query'
669
+ message: `A validation error occurred when validating the ${validationContext}...`,
670
+ // this is the result of the validation library...
671
+ errors: validation
672
+ }
673
+ } else {
674
+ response = {
675
+ message: 'An error occurred...'
676
+ }
677
+ }
678
+
679
+ // any additional work here, eg. log error
680
+ // ...
681
+
682
+ reply.status(statusCode).send(response)
683
+ }
684
+ ```
685
+
686
+ ### Serialization
687
+ <a id="serialization"></a>
688
+
689
+ Fastify uses [fast-json-stringify](https://www.npmjs.com/package/fast-json-stringify)
690
+ to send data as JSON if an output schema is provided in the route options. Using
691
+ an output schema can drastically increase throughput and help prevent accidental
692
+ disclosure of sensitive information.
693
+
694
+ Example:
695
+ ```js
696
+ const schema = {
697
+ response: {
698
+ 200: {
699
+ type: 'object',
700
+ properties: {
701
+ value: { type: 'string' },
702
+ otherValue: { type: 'boolean' }
703
+ }
704
+ }
705
+ }
706
+ }
707
+
708
+ fastify.post('/the/url', { schema }, handler)
709
+ ```
710
+
711
+ The response schema is based on the status code. To use the same schema for
712
+ multiple status codes, use `'2xx'` or `default`, for example:
713
+ ```js
714
+ const schema = {
715
+ response: {
716
+ default: {
717
+ type: 'object',
718
+ properties: {
719
+ error: {
720
+ type: 'boolean',
721
+ default: true
722
+ }
723
+ }
724
+ },
725
+ '2xx': {
726
+ type: 'object',
727
+ properties: {
728
+ value: { type: 'string' },
729
+ otherValue: { type: 'boolean' }
730
+ }
731
+ },
732
+ 201: {
733
+ // the contract syntax
734
+ value: { type: 'string' }
735
+ }
736
+ }
737
+ }
738
+
739
+ fastify.post('/the/url', { schema }, handler)
740
+ ```
741
+ A specific response schema can be defined for different content types.
742
+ For example:
743
+ ```js
744
+ const schema = {
745
+ response: {
746
+ 200: {
747
+ description: 'Response schema that support different content types'
748
+ content: {
749
+ 'application/json': {
750
+ schema: {
751
+ type: 'object',
752
+ properties: {
753
+ name: { type: 'string' },
754
+ image: { type: 'string' },
755
+ address: { type: 'string' }
756
+ }
757
+ }
758
+ },
759
+ 'application/vnd.v1+json': {
760
+ schema: {
761
+ type: 'array',
762
+ items: { $ref: 'test' }
763
+ }
764
+ }
765
+ }
766
+ },
767
+ '3xx': {
768
+ content: {
769
+ 'application/vnd.v2+json': {
770
+ schema: {
771
+ type: 'object',
772
+ properties: {
773
+ fullName: { type: 'string' },
774
+ phone: { type: 'string' }
775
+ }
776
+ }
777
+ }
778
+ }
779
+ },
780
+ default: {
781
+ content: {
782
+ // */* is match-all content-type
783
+ '*/*': {
784
+ schema: {
785
+ type: 'object',
786
+ properties: {
787
+ desc: { type: 'string' }
788
+ }
789
+ }
790
+ }
791
+ }
792
+ }
793
+ }
794
+ }
795
+
796
+ fastify.post('/url', { schema }, handler)
797
+ ```
798
+
799
+ #### Serializer Compiler
800
+ <a id="schema-serializer"></a>
801
+
802
+ The `serializerCompiler` returns a function that must return a string from an
803
+ input object. When defining a response JSON Schema, change the default
804
+ serialization method by providing a function to serialize each route.
805
+
806
+ ```js
807
+ fastify.setSerializerCompiler(({ schema, method, url, httpStatus, contentType }) => {
808
+ return data => JSON.stringify(data)
809
+ })
810
+
811
+ fastify.get('/user', {
812
+ handler (req, reply) {
813
+ reply.send({ id: 1, name: 'Foo', image: 'BIG IMAGE' })
814
+ },
815
+ schema: {
816
+ response: {
817
+ '2xx': {
818
+ type: 'object',
819
+ properties: {
820
+ id: { type: 'number' },
821
+ name: { type: 'string' }
822
+ }
823
+ }
824
+ }
825
+ }
826
+ })
827
+ ```
828
+
829
+ *To set a custom serializer in a specific part of the code, use
830
+ [`reply.serializer(...)`](./Reply.md#serializerfunc).*
831
+
832
+ ### Error Handling
833
+ When schema validation fails for a request, Fastify will automatically return a
834
+ status 400 response including the result from the validator in the payload. For
835
+ example, if the following schema is used for a route:
836
+
837
+ ```js
838
+ const schema = {
839
+ body: {
840
+ type: 'object',
841
+ properties: {
842
+ name: { type: 'string' }
843
+ },
844
+ required: ['name']
845
+ }
846
+ }
847
+ ```
848
+
849
+ If the request fails to satisfy the schema, the route will return a response
850
+ with the following payload:
851
+
852
+ ```js
853
+ {
854
+ "statusCode": 400,
855
+ "error": "Bad Request",
856
+ "message": "body should have required property 'name'"
857
+ }
858
+ ```
859
+
860
+ > ⚠ Security Consideration: By default, validation error details from the schema
861
+ > are included in the response payload. If your organization requires sanitizing
862
+ > or customizing these error messages (e.g., to avoid exposing internal schema
863
+ > details), configure a custom error handler using
864
+ > [`setErrorHandler()`](./Server.md#seterrorhandler).
865
+
866
+ To handle errors inside the route, specify the `attachValidation` option. If
867
+ there is a validation error, the `validationError` property of the request will
868
+ contain the `Error` object with the raw validation result as shown below:
869
+
870
+ ```js
871
+ const fastify = Fastify()
872
+
873
+ fastify.post('/', { schema, attachValidation: true }, function (req, reply) {
874
+ if (req.validationError) {
875
+ // `req.validationError.validation` contains the raw validation error
876
+ reply.code(400).send(req.validationError)
877
+ }
878
+ })
879
+ ```
880
+
881
+ #### `schemaErrorFormatter`
882
+
883
+ To format errors, provide a sync function that returns an error as the
884
+ `schemaErrorFormatter` option when instantiating Fastify. The context function
885
+ will be the Fastify server instance.
886
+
887
+ `errors` is an array of Fastify schema errors `FastifySchemaValidationError`.
888
+ `dataVar` is the currently validated part of the schema (params, body,
889
+ querystring, headers).
890
+
891
+ ```js
892
+ const fastify = Fastify({
893
+ schemaErrorFormatter: (errors, dataVar) => {
894
+ // ... my formatting logic
895
+ return new Error(myErrorMessage)
896
+ }
897
+ })
898
+
899
+ // or
900
+ fastify.setSchemaErrorFormatter(function (errors, dataVar) {
901
+ this.log.error({ err: errors }, 'Validation failed')
902
+ // ... my formatting logic
903
+ return new Error(myErrorMessage)
904
+ })
905
+ ```
906
+
907
+ Use [setErrorHandler](./Server.md#seterrorhandler) to define a custom response
908
+ for validation errors such as:
909
+
910
+ ```js
911
+ fastify.setErrorHandler(function (error, request, reply) {
912
+ if (error.validation) {
913
+ reply.status(422).send(new Error('validation failed'))
914
+ }
915
+ })
916
+ ```
917
+
918
+ For custom error responses in the schema, see
919
+ [`ajv-errors`](https://github.com/ajv-validator/ajv-errors). Check out the
920
+ [example](https://github.com/fastify/example/blob/HEAD/validation-messages/custom-errors-messages.js)
921
+ usage.
922
+
923
+ > Install version 1.0.1 of `ajv-errors`, as later versions are not compatible
924
+ > with AJV v6 (the version shipped by Fastify v3).
925
+
926
+ Below is an example showing how to add **custom error messages for each
927
+ property** of a schema by supplying custom AJV options. Inline comments in the
928
+ schema describe how to configure it to show a different error message for each
929
+ case:
930
+
931
+ ```js
932
+ const fastify = Fastify({
933
+ ajv: {
934
+ customOptions: {
935
+ jsonPointers: true,
936
+ // ⚠ Warning: Enabling this option may lead to this security issue https://www.cvedetails.com/cve/CVE-2020-8192/
937
+ allErrors: true
938
+ },
939
+ plugins: [
940
+ require('ajv-errors')
941
+ ]
942
+ }
943
+ })
944
+
945
+ const schema = {
946
+ body: {
947
+ type: 'object',
948
+ properties: {
949
+ name: {
950
+ type: 'string',
951
+ errorMessage: {
952
+ type: 'Bad name'
953
+ }
954
+ },
955
+ age: {
956
+ type: 'number',
957
+ errorMessage: {
958
+ type: 'Bad age', // specify custom message for
959
+ min: 'Too young' // all constraints except required
960
+ }
961
+ }
962
+ },
963
+ required: ['name', 'age'],
964
+ errorMessage: {
965
+ required: {
966
+ name: 'Why no name!', // specify error message for when the
967
+ age: 'Why no age!' // property is missing from input
968
+ }
969
+ }
970
+ }
971
+ }
972
+
973
+ fastify.post('/', { schema, }, (request, reply) => {
974
+ reply.send({
975
+ hello: 'world'
976
+ })
977
+ })
978
+ ```
979
+
980
+ To return localized error messages, see
981
+ [ajv-i18n](https://github.com/ajv-validator/ajv-i18n).
982
+
983
+ ```js
984
+ const localize = require('ajv-i18n')
985
+
986
+ const fastify = Fastify()
987
+
988
+ const schema = {
989
+ body: {
990
+ type: 'object',
991
+ properties: {
992
+ name: {
993
+ type: 'string',
994
+ },
995
+ age: {
996
+ type: 'number',
997
+ }
998
+ },
999
+ required: ['name', 'age'],
1000
+ }
1001
+ }
1002
+
1003
+ fastify.setErrorHandler(function (error, request, reply) {
1004
+ if (error.validation) {
1005
+ localize.ru(error.validation)
1006
+ reply.status(400).send(error.validation)
1007
+ return
1008
+ }
1009
+ reply.send(error)
1010
+ })
1011
+ ```
1012
+
1013
+ ### JSON Schema support
1014
+
1015
+ JSON Schema provides utilities to optimize schemas. Combined with Fastify's
1016
+ shared schema, all schemas can be easily reused.
1017
+
1018
+ | Use Case | Validator | Serializer |
1019
+ |-----------------------------------|-----------|------------|
1020
+ | `$ref` to `$id` | ️️✔️ | ✔️ |
1021
+ | `$ref` to `/definitions` | ✔️ | ✔️ |
1022
+ | `$ref` to shared schema `$id` | ✔️ | ✔️ |
1023
+ | `$ref` to shared schema `/definitions` | ✔️ | ✔️ |
1024
+
1025
+ #### Examples
1026
+
1027
+ ##### Usage of `$ref` to `$id` in same JSON Schema
1028
+
1029
+ ```js
1030
+ const refToId = {
1031
+ type: 'object',
1032
+ definitions: {
1033
+ foo: {
1034
+ $id: '#address',
1035
+ type: 'object',
1036
+ properties: {
1037
+ city: { type: 'string' }
1038
+ }
1039
+ }
1040
+ },
1041
+ properties: {
1042
+ home: { $ref: '#address' },
1043
+ work: { $ref: '#address' }
1044
+ }
1045
+ }
1046
+ ```
1047
+
1048
+
1049
+ ##### Usage of `$ref` to `/definitions` in same JSON Schema
1050
+ ```js
1051
+ const refToDefinitions = {
1052
+ type: 'object',
1053
+ definitions: {
1054
+ foo: {
1055
+ $id: '#address',
1056
+ type: 'object',
1057
+ properties: {
1058
+ city: { type: 'string' }
1059
+ }
1060
+ }
1061
+ },
1062
+ properties: {
1063
+ home: { $ref: '#/definitions/foo' },
1064
+ work: { $ref: '#/definitions/foo' }
1065
+ }
1066
+ }
1067
+ ```
1068
+
1069
+ ##### Usage `$ref` to a shared schema `$id` as external schema
1070
+ ```js
1071
+ fastify.addSchema({
1072
+ $id: 'http://foo/common.json',
1073
+ type: 'object',
1074
+ definitions: {
1075
+ foo: {
1076
+ $id: '#address',
1077
+ type: 'object',
1078
+ properties: {
1079
+ city: { type: 'string' }
1080
+ }
1081
+ }
1082
+ }
1083
+ })
1084
+
1085
+ const refToSharedSchemaId = {
1086
+ type: 'object',
1087
+ properties: {
1088
+ home: { $ref: 'http://foo/common.json#address' },
1089
+ work: { $ref: 'http://foo/common.json#address' }
1090
+ }
1091
+ }
1092
+ ```
1093
+
1094
+ ##### Usage `$ref` to a shared schema `/definitions` as external schema
1095
+ ```js
1096
+ fastify.addSchema({
1097
+ $id: 'http://foo/shared.json',
1098
+ type: 'object',
1099
+ definitions: {
1100
+ foo: {
1101
+ type: 'object',
1102
+ properties: {
1103
+ city: { type: 'string' }
1104
+ }
1105
+ }
1106
+ }
1107
+ })
1108
+
1109
+ const refToSharedSchemaDefinitions = {
1110
+ type: 'object',
1111
+ properties: {
1112
+ home: { $ref: 'http://foo/shared.json#/definitions/foo' },
1113
+ work: { $ref: 'http://foo/shared.json#/definitions/foo' }
1114
+ }
1115
+ }
1116
+ ```
1117
+
1118
+ ### Resources
1119
+ <a id="resources"></a>
1120
+
1121
+ - [JSON Schema](https://json-schema.org/)
1122
+ - [Understanding JSON
1123
+ Schema](https://json-schema.org/understanding-json-schema/about)
1124
+ - [fast-json-stringify
1125
+ documentation](https://github.com/fastify/fast-json-stringify)
1126
+ - [Ajv documentation](https://github.com/ajv-validator/ajv/blob/master/README.md)
1127
+ - [Ajv i18n](https://github.com/ajv-validator/ajv-i18n)
1128
+ - [Ajv custom errors](https://github.com/ajv-validator/ajv-errors)
1129
+ - Custom error handling with core methods with error file dumping
1130
+ [example](https://github.com/fastify/example/tree/main/validation-messages)