![require(esm) Backported to Node.js 20, Paving the Way for ESM-Only Packages](https://cdn.sanity.io/images/cgdhsj6q/production/be8ab80c8efa5907bc341c6fefe9aa20d239d890-1600x1097.png?w=400&fit=max&auto=format)
Security News
require(esm) Backported to Node.js 20, Paving the Way for ESM-Only Packages
require(esm) backported to Node.js 20, easing the transition to ESM-only packages and reducing complexity for developers as Node 18 nears end-of-life.
fastify-zod
Advanced tools
fastify
is awesome and arguably the best Node http server around.
zod
is awesome and arguably the best TypeScript modeling / validation library around.
Unfortunately, fastify
and zod
don't work together very well. fastify
suggests using @sinclair/typebox
, which is nice but is nowhere close to zod
. This library allows you to use zod
as your primary source of truth for models with nice integration with fastify
, fastify-swagger
and OpenAPI typescript-fetch
generator.
zod
in a single place, without redundancy / conflicting sources of truthfastify
fastify-swagger
and openapitools-generator/typescrip-fetch
enum
sfastify-zod
npm i fastify-zod`
zod
const TodoItemId = z.object({
id: z.string().uuid(),
});
type TodoItemId = z.infer<typeof TodoItemId>;
enum TodoStateEnum {
Todo = `todo`,
InProgress = `in progress`,
Done = `done`,
}
const TodoState = z.nativeEnum(TodoStateEnum);
const TodoItem = TodoItemId.extend({
label: z.string(),
dueDate: z.date().optional(),
state: TodoState,
});
type TodoItem = z.infer<typeof TodoItem>;
const TodoItems = z.object({
todoItems: z.array(TodoItem),
});
type TodoItems = z.infer<typeof TodoItems>;
const TodoItemsGroupedByStatus = z.object({
todo: z.array(TodoItem),
inProgress: z.array(TodoItem),
done: z.array(TodoItem),
});
type TodoItemsGroupedByStatus = z.infer<typeof TodoItemsGroupedByStatus>;
const schema = {
TodoItemId,
TodoItem,
TodoItems,
TodoItemsGroupedByStatus,
};
fastify
types (as recommended by fastify
)import type { FastifyZod } from "fastify-zod";
declare module "fastify" {
interface FastifyInstance {
readonly zod: FastifyZod<typeof schema>;
}
}
import { buildJsonSchemas } from "fastify-zod";
const jsonSchemas = buildJsonSchemas(schema);
fastify-zod
with optional config for fastify-swagger
import { register } from "fastify-zod";
const f = fastify();
register(f, {
jsonSchemas,
swagger: {
routePrefix: `/openapi`,
openapi: {
info: {
title: `Zod Fastify Test Server`,
description: `API for Zod Fastify Test Server`,
version: `0.0.0`,
},
},
exposeRoute: true,
staticCSP: true,
},
});
f.zod.post(
`/item`,
{
operationId: `postTodoItem`,
body: `TodoItem`,
reply: `TodoItems`,
},
async ({ body: nextItem }) => {
/* body is correctly inferred as TodoItem */
if (state.todoItems.some((prevItem) => prevItem.id === nextItem.id)) {
throw new BadRequest(`item already exists`);
}
state.todoItems = [...state.todoItems, nextItem];
/* reply is typechecked against TodoItems */
return state;
}
);
buildJsonSchemas(schema: Schema, options: BuildJsonSchemasOptions = {})
Build JSON Schemas from Zod models.
Schema
Record mapping model keys to Zod types. Keys will be used to reference models in routes definitions.
Example:
const TodoItem = z.object({
/* ... */
});
const TodoList = z.object({
todoItems: z.array(TodoItem),
});
const schema = {
TodoItem,
TodoList,
};
BuildJsonSchemasOptions = {}
BuildJsonSchemasOptions.target = "jsonSchema7"
: jsonSchema7 (default) or openApi3Generates either jsonSchema7
or openApi3
schema. See zod-to-json-schema
.
buildJsonSchema($id: string, Type: ZodType)
(deprecated)Shorthand to buildJsonSchema({ [$id]: Type }).schemas[0]
.
register(f: FastifyInstance, { jsonSchemas, swagger: SwaggerOptions }: RegisterOptions)
Add schemas to fastify
and decorate instance with zod
property to add strongly-typed routes (see fastify.zod
below).
swagger
is optional but recommended as it enables strongly typed client generation together with openapitool-generator
.
fastify.zod.(delete|get|head|options|patch|post|put)(url: string, config: RouteConfig, handler)
Add route with strong typing.
Example:
f.zod.put(
"/:id",
{
operationId: "putTodoItem",
params: "TodoItemId", // this is a key of "schema" object above
body: "TodoItem",
reply: {
description: "The updated todo item",
key: "TodoItem",
},
},
async ({ params: { id }, body: item }) => {
/* ... */
}
);
openapitools
Together with fastify-swagger
, this library supports downstream client code generation using openapitools-generator
.
For this you need to first generate the spec file, then run openapitools-generator
:
const spec = await f
.inject({
method: "get",
url: "/openapi/json",
})
.then((spec) => spec.json());
writeFileSync("openapi-spec.json", JSON.stringify(spec), { encoding: "utf-8" });
We recommend running this as part as the build step of your app, see package.json.
Due to limitations in openapitools-generator
, it is not possible to use JSON pointers (e.g. #!/components/schemas/my-schema/nested/path
). To achieve downstream support, we "flatten" the generated JSON Schema to avoid using pointers. Hence the generated models tend to be relatively verbose, but should yet remain human-readable.
Limitations in openapitools-generator
including discriminated / tagged unions limit the scope of models. Typing, validation, etc., will work as expected, but the generator will fail.
MIT License Copyright (c) 2022 Elie Rotenberg
FAQs
Zod integration with Fastify
We found that fastify-zod demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
require(esm) backported to Node.js 20, easing the transition to ESM-only packages and reducing complexity for developers as Node 18 nears end-of-life.
Security News
PyPI now supports iOS and Android wheels, making it easier for Python developers to distribute mobile packages.
Security News
Create React App is officially deprecated due to React 19 issues and lack of maintenance—developers should switch to Vite or other modern alternatives.