-
-
Notifications
You must be signed in to change notification settings - Fork 339
Incompatible Zod schema shape for oRPC when using orpc + zod plugins #3641
Description
Description
When generating an oRPC contract using @hey-api/openapi-ts with both the orpc and zod plugins enabled, the generated Zod input schema does not match the structure expected by oRPC for putStructure: 'detailed'.
Specifically, path parameters are generated under a path key, while oRPC expects them under params. This mismatch causes the generated contract to be incompatible with oRPC without manual adjustments.
Usecase: I am generating a oRPC contract for a server implementation.
// openapi-ts.config.ts
import { defineConfig } from "@hey-api/openapi-ts";
export default defineConfig({
input: "https://raw.githubusercontent.com/swagger-api/swagger-petstore/master/src/main/resources/openapi.yaml",
output: {
path: "./src/client",
},
plugins: ["orpc", "zod"],
});This currently generates the following code:
// orpc.gen.ts
// ...
export const getPetById = base.route({
description: 'Returns a single pet.',
method: 'GET',
operationId: 'getPetById',
path: '/pet/{petId}',
summary: 'Find pet by ID.',
tags: ['pet']
}).input(zGetPetByIdData).output(zGetPetByIdResponse);
// ...// zod.gen.ts
// ...
export const zGetPetByIdData = z.object({
body: z.never().optional(),
path: z.object({
petId: z.coerce.bigint().min(BigInt('-9223372036854775808'), { error: 'Invalid value: Expected int64 to be >= -9223372036854775808' }).max(BigInt('9223372036854775807'), { error: 'Invalid value: Expected int64 to be <= 9223372036854775807' })
}),
query: z.never().optional()
});
// ...The generated orpc.gen.ts looks good, however, it is not compatible with the generated zod.gen.ts.
My oRPC server implementation raises a validation error, when I send a request:
{"defined":false,"code":"BAD_REQUEST","status":400,"message":"Input validation failed","data":{"issues":[{"expected":"object","code":"invalid_type","path":["path"],"message":"Invalid input: expected object, received undefined"},{"expected":"never","code":"invalid_type","path":["query"],"message":"Invalid input: expected never, received object"}]}}
Expected behavior:
a) orpc.gen.ts does not use zod.gen.ts to import schemas for input validation or b) zod.gen.ts is generated slightly different when used together with the orpc plugin:
queryshould be anz.object({})without members, if the endpoint has no query params.pathneeds to be calledparams.
When I manually change zod.gen.ts to look like this, oRPC Server stops to complain:
// zod.gen.ts
// ...
export const zGetPetByIdData = z.object({
body: z.never().optional(),
/*path*/ params: z.object({
petId: z.coerce
.bigint()
.min(BigInt("-9223372036854775808"), { error: "Invalid value: Expected int64 to be >= -9223372036854775808" })
.max(BigInt("9223372036854775807"), { error: "Invalid value: Expected int64 to be <= 9223372036854775807" }),
}),
query: /*z.never().optional()*/ z.object({}),
});
// ...Thanks for your work on this project!
Reproducible example or configuration
https://stackblitz.com/edit/hey-api-example-h1wa7hud
OpenAPI specification (optional)
No response
System information (optional)
@hey-api/openapi-ts: 0.94.4
@orpc/contract: 1.13.10
@orpc/openapi: 1.13.10
@orpc/server: 1.13.10
zod: 4.3.6