@woodle/zod-openapi
v1.0.4
Published
Zod to OpenAPI converter
Readme
Forked from https://github.com/anatine/zod-plugins to add support for components with $ref See: https://github.com/anatine/zod-plugins/pull/130
@woodle/zod-openapi
Converts a Zod schema to an OpenAPI SchemaObject as defined by openapi3-ts
Installation
Both openapi3-ts and zod are peer dependencies instead of dependant packages.
While zod is necessary for operation, openapi3-ts is for type-casting.
yarn add openapi3-ts zod @woodle/zod-openapiUsage
Take any Zod schema and convert it to an OpenAPI JSON object
import { generateSchema } from '@woodle/zod-openapi';
const aZodSchema = z.object({
uid: z.string().nonempty(),
firstName: z.string().min(2),
lastName: z.string().optional(),
email: z.string().email(),
phoneNumber: z.string().min(10).optional(),
})
const myOpenApiSchema = generateSchema(aZodSchema);
// ...This will generate an OpenAPI schema for myOpenApiSchema
{
"type": "object",
"properties": {
"uid": {
"type": "string",
"minLength": 1
},
"firstName": {
"type": "string",
"minLength": 2
},
"lastName": {
"type": "string"
},
"email": {
"type": "string",
"format": "email"
},
"phoneNumber": {
"type": "string",
"minLength": 10
}
},
"required": [
"uid",
"firstName",
"email"
]
}Extend a Zod schema with additional OpenAPI schema via a function wrapper
import { extendApi, generateSchema } from '@woodle/zod-openapi';
const aZodExtendedSchema = extendApi(
z.object({
uid: extendApi(z.string().nonempty(), {
title: 'Unique ID',
description: 'A UUID generated by the server',
}),
firstName: z.string().min(2),
lastName: z.string().optional(),
email: z.string().email(),
phoneNumber: extendApi(z.string().min(10), {
description: 'US Phone numbers only',
example: '555-555-5555',
}),
}),
{
title: 'User',
description: 'A user schema',
}
);
const myOpenApiSchema = generateSchema(aZodExtendedSchema);
// ...... or via extension of the Zod schema:
import { extendApi, generateSchema, extendZodWithOpenApi } from '@woodle/zod-openapi';
import {z} from 'zod';
extendZodWithOpenApi(z);
const aZodExtendedSchema =
z.object({
uid: z.string().nonempty().openapi({
title: 'Unique ID',
description: 'A UUID generated by the server',
}),
firstName: z.string().min(2),
lastName: z.string().optional(),
email: z.string().email(),
phoneNumber: z.string().min(10).openapi({
description: 'US Phone numbers only',
example: '555-555-5555',
}),
}).openapi(
{
title: 'User',
description: 'A user schema',
}
);
const myOpenApiSchema = generateSchema(aZodExtendedSchema);
// ...This will generate an extended schema:
{
"type": "object",
"properties": {
"uid": {
"type": "string",
"minLength": 1,
"title": "Unique ID",
"description": "A UUID generated by the server"
},
"firstName": {
"type": "string",
"minLength": 2
},
"lastName": {
"type": "string"
},
"email": {
"type": "string",
"format": "email"
},
"phoneNumber": {
"type": "string",
"minLength": 10,
"description": "US Phone numbers only",
"example": "555-555-5555"
}
},
"required": [
"uid",
"firstName",
"email",
"phoneNumber"
],
"title": "User",
"description": "A user schema"
}And why we are even here, using $ref,
// Make sure to use extendZodWithOpenApi() from @woodle/zod-nestjs
import { fragmentName } from '@woodle/zod-openapi';
const InternalSchema = extendApi(z.object({
baz: z.string(),
}), {
[fragmentName]: 'InternalSchemaDto'
})
export class InternalSchemaDto extends createZodDto(InternalSchema) { }
const MySchema = extendApi(z.object({
foo: z.string()
bar: InternalSchema,
})
class MySchemaDto extends createZodDto(MySchema) { }
@Controller()
@UsePipes(ZodValidationPipe)
@ApiExtraModels(InternalSchemaDto) // Must add referenct for Dto's that are not directly used.
export class AppController {
constructor() { }
@Post('hello')
hello(@Body() body: MySchema) {
return;
}
}Produces:
{
"InternalSchemaDto": {
"type": "object",
"properties": {
"baz": {
"type": "string"
}
},
"required": [
"baz"
]
},
"MySchemaDto": {
"type": "object",
"properties": {
"foo": {
"type": "string"
},
"bar": {
"$ref": "#/components/schemas/InternalSchemaDto"
}
},
"required": [
"foo",
"bar"
]
}
}Credits
anatine/zod-plugins
express-zod-api
A great lib that provided some insights on dealing with various zod types.
zod-dto
Lib providing insights into using Zod with NestJS
