Skip to navigation

Zod OpenAPI

Zod-OpenAPI Integration Issues

We attempted to integrate Zod with OpenAPI using the zod-openapi library to automatically generate OpenAPI documentation while maintaining type-safe runtime validation. The integration aimed to streamline the development process by using Zod for both validation and documentation generation.

Challenges Encountered

  1. Issue with $ref and required Fields:
    • When using Zod schemas, the generated JSON schema often contained $ref references to the definitions object, which Fastify could not resolve, resulting in errors such as:
      • can't resolve reference #/definitions/UserSchema.

      • data/required must be array — Fastify requires required to be an array of field names (e.g., ['id', 'name', 'email']), but zod-openapi didn’t automatically format the required field as an array.

      • here is the screenshot of the error: image.png

  2. JSON Schema Generation:
    • The Zod-to-JSON Schema conversion using zod-openapi was producing an incorrect schema format that Fastify couldn’t interpret. Specifically, the properties field was not properly set, and $ref was incorrectly being used in the schema, which Fastify doesn’t support.

Converting this zod schema object by using zodToJsonSchema(UserSchema, 'UserSchema');

const UserSchema = z.object({
  id: z.uuid(),
  name: z.string().min(1),
  email: z.email(),
}).strict();

will result to:

{"$ref":"#/definitions/UserSchema","definitions":{"UserSchema":{"type":"string"}},"$schema":"http://json-schema.org/draft-07/schema#"}
  1. OpenAPI Documentation Integration:
    • While zod-openapi generated the OpenAPI documentation correctly in most cases, Fastify’s Swagger plugin required the schema to be in a specific format, causing issues when trying to directly integrate Zod schemas into Fastify’s schema validation system.

##Sample proof-of-concept Code

import { z } from 'zod';
import { extendZodWithOpenApi } from '@hono/zod-openapi';
extendZodWithOpenApi(z);
const UserSchema = z.object({
id: z.string().uuid({ message: 'Invalid UUID format' }),
name: z.string().min(1, { message: 'Name is required' }),
email: z.string().email({ message: 'Invalid email address' }),
});
const CreateUserResponse = UserSchema.openapi({
description: 'Response after creating a user',
});
export const routes = async (frameworkServer: FastifyInstance) => {
frameworkServer.post('/demo/user', {
schema: {
body: UserSchema, // Zod schema for the request body
response: {
201: CreateUserResponse,
},
},
handler: async (request, reply) => {
const { id, name, email } = UserSchema.parse(request.body);
reply.status(201).send({ id, name, email });
},
});
}

zod-openapi is not specifically designed for Fastify, it is primarily intended for OpenAPI documentation generation from Zod schemas.