Documentation should contain a note and type provider agnostic example for the usage of formats
- Dominant language
- JavaScript
- Stars
- 243
- Forks
- 26
- Avg merge
- 1m
- Merged PRs (30d)
- 1
Description
### Prerequisites
- [x] I have written a descriptive issue title
- [x] I have searched existing issues to ensure the issue has not already been raised
### Issue
## Background
I was setting Fastify for the first time around. While integrating `@fastify/env`, the application kept throwing an unknown format error:
```
unknown format "uuid" ignored in schema at path "#/properties/ID"
```
After some experimentation and going through both the `fastify` and `@fastify/env` documentation, I realised:
1. The vaildation on API schemas were working as expected.
2. The validation on APIs were handled by typebox (in my case), while the validation in `@fastify/env` are handled by `ajv`
## Ask
It is completely understandable why formats are not handled in the plugin. However, I believe there at least should be some documentation on the matter.
Below I have added an example documentation section that would have helped me a bunch.
### Formats
Formats need to be explicitly added to ajv instance:
```typescript
await app.register(import("@fastify/env"), {
confKey: 'config',
schema: Type.Object({
CUSTOM: Type.String({ format: 'customFormat' })
}),
ajv: {
customOptions: (ajvInstance) => {
ajvInstance.addFormat('customFormat', (c) => c === "custom")
return ajvInstance;
}
}
})
```
## Reproducible Example
tsconfig.json
```jsonc
{
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist",
"module": "nodenext",
"target": "esnext",
"lib": ["esnext"],
"types": ["node"],
"sourceMap": true,
"declaration": false,
"declarationMap": false,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"strict": true,
"jsx": "react-jsx",
"verbatimModuleSyntax": true,
"isolatedModules": true,
"noUncheckedSideEffectImports": true,
"moduleDetection": "force",
"skipLibCheck": true
}
}
```
package.json
```json
{
"name": "fastify-validation",
"version": "1.0.0",
"description": "",
"type": "module",
"main": "index.js",
"scripts": {
"dev": "tsx watch src/index.ts"
},
"keywords": [],
"author": "",
"license": "ISC",
"packageManager": "pnpm@10.28.0",
"dependencies": {
"@fastify/env": "^5.0.3",
"@fastify/type-provider-typebox": "^6.1.0",
"fastify": "^5.7.1"
},
"devDependencies": {
"@types/node": "^25.0.9",
"tsx": "^4.21.0",
"typescript": "^5.9.3"
}
}
```
src/index.ts
```typescript
import { Type, TypeBoxValidatorCompiler, type TypeBoxTypeProvider } from "@fastify/type-provider-typebox";
import Fastify, { type FastifyInstance } from "fastify";
function routes(app: FastifyInstance) {
app.get(
"/:id",
{
schema: {
tags: ["System"],
description: "Check the server status",
params: Type.Object({
id: Type.String({ format: "uuid" })
}),
response: {
200: Type.Object({ message: Type.Literal("success") }),
},
},
},
async () => {
return {
message: "success",
};
},
);
}
async function start() {
const app = Fastify({ logger: true })
.withTypeProvider()
.setValidatorCompiler(TypeBoxValidatorCompiler);
try {
await app.register(routes)
await app.register(import("@fastify/env"), {
confKey: 'config',
schema: Type.Object({
ID: Type.String({ format: 'uuid' })
}),
})
await app.ready()
await app.listen({ port: 5000, host: "::" });
app.log.info("Server is running");
} catch (e) {
app.log.error(e);
process.exit(1);
}
}
start();
```
### My Solution
```diff
diff --git a/src/index.ts b/src/index.ts
index e48e450..9b1cfbf 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,4 +1,4 @@
-import { Type, TypeBoxValidatorCompiler, type TypeBoxTypeProvider } from "@fastify/type-provider-typebox";
+import { Format, Type, TypeBoxValidatorCompiler, type TypeBoxTypeProvider } from "@fastify/type-provider-typebox";
import Fastify, { type FastifyInstance } from "fastify";
function routes(app: FastifyInstance) {
@@ -36,6 +36,14 @@ async function start() {
schema: Type.Object({
ID: Type.String({ format: 'uuid' })
}),
+ ajv: {
+ customOptions: (ajvInstance) => {
+ Format.Entries().forEach((format) => {
+ ajvInstance.addFormat(...format)
+ })
+ return ajvInstance;
+ }
+ }
})
await app.ready()
await app.listen({ port: 5000, host: "::" });
```
Contributor guide
Assessment
This issue has not been assessed yet.