@asteasolutions/zod-to-openapiの問題
@hono/zod-openapi
は@asteasolutions/zod-to-openapi
というライブラリに依存しており、このライブラリはz.lazy
をサポートしていません。
Drizzle Zod + lazy · Issue #255 · asteasolutions/zod-to-openapi
回避策として、以下のように.openapiを手動で定義する方法が提案されています。
BaseSearchOrdersFiltersSchema.extend({
oneOf: z
.lazy(() => SearchOrdersFiltersSchema.array().optional())
.openapi({
type: "array",
items: {
type: "object",
},
}),
より効率的なワークアラウンド
しかし、上記の方法ではZodでスキーマを定義する恩恵を完全に得られないため、zod-to-json-schemaを使うことができます。
import { serve } from "@hono/node-server";
import { swaggerUI } from "@hono/swagger-ui";
import { createRoute, OpenAPIHono } from "@hono/zod-openapi";
import { z } from "@hono/zod-openapi";
import { zodToJsonSchema } from "zod-to-json-schema";
const baseCategorySchema = z.object({ name: z.string() });
type Category = z.infer<typeof baseCategorySchema> & {
subcategories: Category[];
};
const categorySchemaRaw: z.ZodType<Category> = baseCategorySchema.extend({
subcategories: z.lazy(() => categorySchemaRaw.array()),
});
const name = "Category";
const jsonSchema = zodToJsonSchema(categorySchemaRaw, {
basePath: [`#/components/schemas/${name}`],
});
// console.dir(jsonSchema, { depth: null });
const schema = categorySchemaRaw.openapi(name, jsonSchema as {}).openapi({
example: {
name: "test1",
subcategories: [
{
name: "test2",
subcategories: [],
},
],
},
});
const app = new OpenAPIHono({ strict: false });
app.openapi(
createRoute({
method: "post",
path: "/test",
request: { body: { content: { "application/json": { schema } } } },
responses: { 200: { description: "test" } },
}),
(c) => c.text("test"),
);
type OpenAPIObjectConfig = Parameters<typeof app.getOpenAPIDocument>[0];
const config: OpenAPIObjectConfig = {
openapi: "3.0.3",
info: { version: "0.0.1", title: "Some API" },
};
const pathOpenAPI = "/openapi";
app.doc(pathOpenAPI, config);
app.get("/swagger-ui", swaggerUI({ url: pathOpenAPI }));
serve({
async fetch(req, env) {
return app.fetch(req, env);
},
port: 4001,
});
// eslint-disable-next-line no-console
console.log(`Server is running on port 4001`);
// const schemaOpenAPI = app.getOpenAPIDocument(config);
// console.dir(schemaOpenAPI, { depth: null });
samchungy/zod-openapiに移行する提案
@hono/zod-openapi
は@samchungy/zod-openapi
に依存を移行することでz.lazy
をサポートすることができます。