We can use a tool called orval
to generate Zod schemas from an OpenAPI specification. We can configure Orval like so:
/* eslint-disable no-undef */
module.exports = {
'busy-bee': {
output: {
client: 'zod',
mode: 'single',
target: './src/schemas.ts',
},
input: {
target: './openapi.json',
},
},
};
And then when we run npx orval --config orval.config.cjs
, we’ll get the following output.
/**
* Generated by orval v7.7.0 🍺
* Do not edit manually.
* Busy Bee API
* API for managing tasks
* OpenAPI spec version: 1.0.0
*/
import { z as zod } from 'zod';
/**
* Retrieve all tasks, optionally filtered by completion status
* @summary Get all tasks
*/
export const getTasksQueryParams = zod.object({
completed: zod.boolean().optional().describe('Filter tasks by completion status'),
});
export const getTasksResponseItem = zod.object({
id: zod.number(),
title: zod.string(),
description: zod.string().optional(),
completed: zod.boolean().optional(),
});
export const getTasksResponse = zod.array(getTasksResponseItem);
/**
* Add a new task to the database
* @summary Create a new task
*/
export const postTasksBody = zod
.object({
title: zod.string(),
description: zod.string().optional(),
})
.describe('Data required to create a new task');
/**
* Retrieve a single task by its ID
* @summary Get a task by ID
*/
export const getTasksIdParams = zod.object({
id: zod.number().describe('ID of the task to retrieve'),
});
export const getTasksIdResponse = zod
.object({
id: zod.number(),
title: zod.string(),
description: zod.string().optional(),
completed: zod.boolean().optional(),
})
.describe('A task item');
/**
* Update an existing task by its ID
* @summary Update a task
*/
export const putTasksIdParams = zod.object({
id: zod.number().describe('ID of the task to update'),
});
export const putTasksIdBody = zod
.object({
title: zod.string().optional(),
description: zod.string().optional(),
completed: zod.boolean().optional(),
})
.describe('Data for updating an existing task');
/**
* Delete a task by its ID
* @summary Delete a task
*/
export const deleteTasksIdParams = zod.object({
id: zod.number().describe('ID of the task to delete'),
});
Not exactly the same as what we wrote by hand, but very, very close.