v5.0.0
zod-to-openapi v5.0.0 is finally here 🎉
What's Changed
- Automatic registration of schemas through the
.openapi
method - Introduced separate generators for different OpenAPI versions
Full Changelog: v4.8.0...v5.0.0
Migrating to v5.0.0
How to use the separated generators
Lets say you had something like this:
import { OpenAPIRegistry, OpenAPIGenerator } from '@asteasolutions/zod-to-openapi';
const registry = new OpenAPIRegistry();
// Register definitions here
const generator = new OpenAPIGenerator(registry.definitions, '3.0.0');
generator.generateDocument({
info: {},
servers: [{ ... }],
});
When migrating to v5.0.0 it would start to look like this:
// Change the import from OpenAPIGenerator to OpenAPIGeneratorV3
import { OpenAPIRegistry, OpenAPIGeneratorV3 } from '@asteasolutions/zod-to-openapi';
const registry = new OpenAPIRegistry();
// Register definitions here
// Do not pass the specific OpenAPI version to the constructor - just definitions
const generator = new OpenAPIGeneratorV3(registry.definitions);
generator.generateDocument({
// Pass the specific OpenAPI version here in the config instead. This would not influence the
// behavior of the generator - it is just the `openapi` value to be returned in tour document.
openapi: '3.0.0',
info: {},
servers: [{ ... }],
});
And similarly if you were using the generator as:
const generator = new OpenAPIGenerator(registry.definitions, '3.1.0');
the respective change would be to start using:
const generator = new OpenAPIGeneratorV31(registry.definitions);
generator.generateDocument({ openapi: '3.1.0', ... })`
Taking advantage of the automatic registration and how to use it
Registering schemas has never been easier.
Let's say you had an example registered schema like
const schema = registry.register(
'Schema',
z.string().openapi({ description: 'Some string' })
);
This is still valid. However an alternative approach to writing this can now be used:
const schema = z.string().openapi('Schema', { description: 'Some string' });
Notice how there is no registry involved. And that is the idea. Thanks to this approach we can do the following:
const entrySchema = z
.object({
key: z.string().openapi('Key', { description: 'Some string' }),
person: z.object({ name: z.string(), age: z.number() }).openapi('User'),
})
.openapi('UserEntry');
// and you can directly pass the schema to the generator if you want:
const generator = new OpenApiGeneratorV3([entrySchema]);
const generateDocument = generator.generateComponents();
This would produce the following result:
{
"components": {
"schemas": {
"Key": { "type": "string", "description": "Some string" },
"User": {
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "number" }
},
"required": ["name", "age"]
},
"UserEntry": {
"type": "object",
"properties": {
"key": { "$ref": "#/components/schemas/Key" },
"person": { "$ref": "#/components/schemas/User" }
},
"required": ["key", "person"]
}
}
}
}
The key part here is that in the example above we've only passed the entrySchema
. However @asteasolutions/zod-to-openapi
would generate and reference any schema that has an identifier (the first parameter of .openapi
) - in the example above - Key
and User
.
Going one step further this would allow any user to not pass in zod schemas to the generator at all. You can only pass route definitions and @asteasolutions/zod-to-openapi
would take care of all the referenced schemas on it's own:
For example, using the example above but changing the generator constructor we can have:
registry.registerPath({
method: 'get',
path: '/users',
responses: {
200: {
description: 'User results',
content: {
'application/json': {
schema: z.array(entrySchema),
},
},
},
},
});
// Notice how entrySchema is not passed at all
const generator = new OpenApiGeneratorV3(registry.definitions);
const generateDocument = generator.generateDocument({
/* your document config here*/
});
This would produce the exact same result for component/schemas
and the path would just look like this
"paths": {
"/users": {
"get": {
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/UserEntry"
}
}
}
}
}
}
}
}
}