fix(open-api): generate requestBody for intersection body schemas#9883
fix(open-api): generate requestBody for intersection body schemas#9883sanidhyasin wants to merge 2 commits into
Conversation
Endpoints whose body schema is built with `z.object({...}).and(z.record(...))`
produce a `ZodIntersection`, which the OpenAPI generator did not handle. As a
result `getRequestBody` returned `undefined` and the operation was emitted
without a `requestBody` (e.g. `/sign-in/email-otp`).
Resolve the intersection by merging its object members into `properties` and
representing a record catch-all as `additionalProperties`, so the request body
is documented as expected.
Closes better-auth#9679
|
@sanidhyasin is attempting to deploy a commit to the better-auth Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR fixes OpenAPI generation for endpoints whose request body schema is a Zod intersection (notably z.object(...).and(z.record(...))), ensuring the resulting operations include a requestBody.
Changes:
- Add OpenAPI generator support for
ZodIntersectionrequest bodies by flattening intersected object properties and representing records viaadditionalProperties. - Add a regression test covering
/sign-in/email-otpto ensurerequestBodyis generated and contains expected fields. - Add a changeset documenting the patch-level behavior change.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| packages/better-auth/src/plugins/open-api/generator.ts | Adds intersection-aware requestBody generation via resolveIntersectionSchema. |
| packages/better-auth/src/plugins/open-api/open-api.test.ts | Adds a regression test verifying requestBody generation for intersection schemas. |
| .changeset/open-api-intersection-request-body.md | Documents the patch change in release notes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
1 issue found across 3 files
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
Address review feedback on intersection request-body generation:
- Deduplicate `required` so intersecting objects that share a property name
don't emit duplicate keys (JSON Schema requires them to be unique).
- Map a record member to its processed value-type schema instead of always
`additionalProperties: true`, preserving type info (e.g. `z.record(z.string(),
z.number())` -> `additionalProperties: { type: "number" }`). `true` is still
used for unconstrained value types (`z.any()`/`z.unknown()`).
Description
Endpoints whose request body is built with an intersection —
z.object({...}).and(z.record(z.string(), z.any()))— produce a ZodZodIntersection. The OpenAPI generator'sgetRequestBodyonly handledZodObject/ZodOptional, so for these endpoints it fell through and returnedundefined, emitting the operation without arequestBody.The most visible case is
POST /sign-in/email-otp(theemailOTPplugin), whose body is:Its generated spec was missing the
requestBodyentirely.Fix
Add a
ZodIntersectionbranch togetRequestBody, backed by a smallresolveIntersectionSchemahelper that:properties(preservingrequiredfor non-optional fields), andz.record(...)catch-all member asadditionalProperties: true.The existing
ZodObject/ZodOptionalpath is left untouched, so no other operation's output changes. Endpoints that already declare an explicitmetadata.openapi.requestBody(e.g./sign-up/email) continue to short-circuit as before.Tests
Added a regression test (
open-api.test.ts) that registers theemailOTPplugin and asserts/sign-in/email-otpnow has arequestBodywithemail/otprequired,nameoptional, andadditionalProperties: true.pnpm typecheckand biome both pass.Closes #9679
Note: the linked duplicate #9298 is closed but no fix has landed on
main/next.Summary by cubic
Fix the OpenAPI generator to include requestBody for intersection body schemas (
z.object(...).and(z.record(...))), so endpoints likePOST /sign-in/email-otpare documented correctly. Also dedupes required keys and preserves record value types inadditionalProperties.ZodIntersectioningetRequestBodyviaresolveIntersectionSchema.propertieswith accurate, dedupedrequired; mapz.record(...)toadditionalPropertiesusing the processed value type (fallback totrueforz.any()/z.unknown()).ZodObject/ZodOptionalbehavior and explicitmetadata.openapi.requestBodyoverrides unchanged./sign-in/email-otpnow emits a properrequestBody.Written for commit ddaeae5. Summary will update on new commits.