openapi2zod v0.2.3
openapi2zod
Convert OpenAPI schemas to Zod schemas effortlessly.
Description
openapi2zod is a utility library that converts OpenAPI JSON schemas into Zod schemas. This allows developers to leverage the power of Zod for schema validation and parsing in their TypeScript projects.
Whether you're working with APIs and need to validate incoming data against your OpenAPI definitions, or you're integrating with tools like Vercel AI, openapi2zod simplifies the process by generating Zod schemas directly from your OpenAPI JSON.
Features
- Easy Conversion: Convert OpenAPI JSON schemas to Zod schemas with minimal effort.
- TypeScript Support: Strongly typed schemas for better developer experience.
- Flexible Integration: Use the generated Zod schemas in any context where Zod is supported.
- Supports OpenAPI 3.x: Compatible with OpenAPI 3.x specifications.
Installation
Install openapi2zod using npm:
npm i openapi2zod
or with yarn
yarn add openapi2zod
or with pnpm
pnpm i openapi2zod
Usage
You can import the generated bundle to use the whole library generated by this starter:
import { parseOpenApiToZod } from "openapi2zod";
// Convert OpenAPI properties to Zod schema
const zodRecords = parseOpenApiToZod(openapiSchema);
for (const [name, schema] of Object.entries(zodRecords)) {
// Current schema metadata, if defined.
const metadata = {};
try {
Object.assign(metadata, JSON.parse(schema._def.description || ''));
} catch (e) {
console.log(`[Dynamic Tool Generation] :: Error parsing metadata for ${name}. Skipping...`);
continue;
}
// Current schema parameters, see our test-cases for various HTTP verbs both with requestBody and parameters.
const requestArgs = schema,
{ description, operationId, path, method } = metadata;
console.log({
name,
description,
operationId,
path,
method,
requestArgs
});
// Do the rest of operation you needed with fetch etc..
}
Example with Vercel AI
Here's an example of how to use openapi2zod
with Vercel AI to dynamically generate tools from an OpenAPI URL:
'use server';
import { CoreTool, tool } from 'ai';
import { unstable_noStore as noStore } from 'next/cache';
import { parseOpenApiToZod } from "openapi2zod";
// Define a type for tools with execute defined
type ExecutableTool = CoreTool<any, any> & {
execute: (args: any) => PromiseLike<any>;
};
export async function generateAIToolByOpenApiUrl(openapiUrl: string, headers?: Record<string, string>) {
/**
* Deal with nextjs static caching
* @see {@link https://github.com/vercel/storage/issues/510}
*/
noStore();
console.log(`[Dynamic Tool Generation] :: Fetching OpenAPI schema from ${openapiUrl}`);
// Fetch OpenAPI schema from the given URL
const openapiSchema = await fetch(openapiUrl, {
cache: "no-cache",
headers,
}).then((res) => res.json());
// Convert OpenAPI properties to Zod schema
const zodRecords = parseOpenApiToZod(openapiSchema);
// Output result
const result: Record<string, ExecutableTool> = {};
for ( const [name, schema] of Object.entries(zodRecords) ) {
// Current schema description, if defined.
const metadata: Record<string, string | undefined> = {};
try {
Object.assign(metadata, JSON.parse(schema._def.description || ''));
}
catch (e) {
console.log(`[Dynamic Tool Generation] :: Error parsing metadata for ${name}. Skipping...`);
continue;
}
if ( !metadata ) {
console.log(`[Dynamic Tool Generation] :: No metadata found for ${name}. Skipping...`);
continue;
}
// Current schema parameters, see our test-cases for various http verbs both with requestBody and parameters.
const requestArgs = schema,
{ description, operationId, path, method } = metadata,
serverUrl = openapiSchema.servers?.[0]?.url || ( new URL(openapiUrl) ).origin;
if ( !operationId || !description || !path || !method ) {
console.log(`[Dynamic Tool Generation] :: Missing required metadata for ${name}. Skipping...`);
continue;
}
const extTool = tool({
description: description,
parameters: requestArgs,
execute: async (params) => {
// Determine the request options
const options: RequestInit = {
method,
headers: {
'Content-Type': 'application/json',
...headers,
},
};
// For GET and DELETE, include params as query string instead of request body
let url = `${serverUrl}${path}`;
if (["GET", "DELETE"].includes(method.toUpperCase())) {
const queryParams = new URLSearchParams(params).toString();
url = queryParams ? `${url}?${queryParams}` : url;
} else {
// Only add `body` for methods that support it (POST, PUT, PATCH)
options.body = JSON.stringify(params);
}
// Make the request using fetch
const response = await fetch(url, options);
console.log(`[Dynamic Tool Call] :: Request to ${url} returned status ${response.status}`);
const result = await response.json();
// Return response in a standardized format
return result;
},
});
// Add the tool to the result.
result[operationId] = extTool;
}
return result;
}
export default generateAIToolByOpenApiUrl;
This example demonstrates how to fetch an OpenAPI schema, convert it to Zod schemas, and dynamically generate tools that can be used with Vercel AI.
Contributing
Contributions are welcome! If you'd like to contribute to openapi2zod
, please open an issue or submit a pull request on GitHub.
NPM scripts
npm t
: Run test suitenpm start
: Runnpm run build
in watch modenpm run test:watch
: Run test suite in interactive watch modenpm run test:prod
: Run linting and generate coveragenpm run build
: Generate bundles and typings, create docsnpm run lint
: Lints codenpm run commit
: Commit using conventional commit style (husky will tell you to use it if you haven't :wink:)
License
This project is licensed under the MIT License.
Acknowledgments
This project was created with TypeScript Library Starter.
Contact
If you have any questions or issues, please open an issue on the GitHub repository.