Skip to content

fix(zod): handle content-type with charset suffix - #3433

Merged
melloware merged 1 commit into
orval-labs:masterfrom
wadakatu:fix/3285-zod-content-type-charset
May 24, 2026
Merged

fix(zod): handle content-type with charset suffix#3433
melloware merged 1 commit into
orval-labs:masterfrom
wadakatu:fix/3285-zod-content-type-charset

Conversation

@wadakatu

@wadakatu wadakatu commented May 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #3285.

packages/zod/src/index.ts was looking up application/json and multipart/form-data by exact key, so:

  • request/response bodies declared as application/json; charset=utf-8 (or any other media-type parameter) silently fell through and no Zod parser was generated, and
  • vendor JSON subtypes like application/geo+json, application/ld+json, application/vnd.api+json were ignored even though they are valid JSON.

This PR introduces a small isMediaType helper that strips media-type parameters and matches with a regex (^application/([^/;]+\+)?json$ for JSON, ^multipart/form-data$ for form data), so all of the above now produce the same Zod schemas as the bare application/json case.

Test Plan

  • New regression test in packages/zod/src/zod.test.ts covering both shapes (multipart/form-data, parameterized JSON).
  • 20 generated Zod snapshots under tests/__snapshots__/.../*.zod.ts are updated — the same petstore spec exposes a ListPetsResponseItem/ListPetsResponse that previously wasn't generated because its response key carried a charset suffix.
  • bun run format:check, bun run build, bun run typecheck, bun run lint, bun run test, bun run test:snapshots, bun run --filter orval-tests build all green locally.

Notes for reviewers

Supersedes #3404 and #3430 — both PRs implement the same packages/zod/src/index.ts change. This PR takes the zod fix and the legitimate tests/__snapshots__/ drift from those, and leaves samples/** untouched. (The samples/** undefinedvoid 0 substitutions in #3430 were producing snapshot mismatches on CI because the orval mock generator only emits undefined; see #3430 (comment) for the full diagnosis.)

Full credit to @pierre-isabel-bbc for the original fix in #3404 and @melloware for picking it up in #3430 — both are tagged as co-authors on the commit.

Summary by CodeRabbit

  • New Features

    • Enhanced JSON content type detection to support vendor-specific JSON formats (e.g., application/*+json) and charset parameters in media types.
    • Added response schema generation for API endpoints across multiple configurations.
  • Tests

    • Added test coverage for content type handling with charset suffixes.

Review Change Stack

Match `application/json` and `multipart/form-data` content keys
when they include parameters such as `; charset=utf-8`, and
recognise vendor JSON subtypes (`application/*+json`, e.g.
`application/geo+json`, `application/vnd.api+json`) so their
response/request schemas are generated as well.

Fixes orval-labs#3285

Co-authored-by: Pierre Isabel <205639300+pierre-isabel-bbc@users.noreply.github.com>
Co-authored-by: melloware <4399574+melloware@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 24, 2026 15:44
@coderabbitai

coderabbitai Bot commented May 24, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

parseBodyAndResponse now uses regex matching to detect JSON media types (including vendor variants like +json) and multipart form-data, normalizing content-type values by stripping parameters. New test validates charset-suffixed types. Response schemas regenerated across all test fixtures.

Changes

Content-type parsing and response schema generation

Layer / File(s) Summary
Media type regex matching and content-type normalization
packages/zod/src/index.ts
Updated parseBodyAndResponse to match JSON via regex pattern against normalized media types (handling application/...json and +json variants). New isMediaType helper extracts and lowercases base media type before parameter stripping.
Test validation for charset-aware content-type detection
packages/zod/src/zod.test.ts
Added test case validating that multipart/form-data; charset=utf-8 and application/json; charset=utf-8 are correctly parsed, with request and response schema generation enabled.
Generated response schemas - all fixtures
tests/__snapshots__/default/..., tests/__snapshots__/hono/..., tests/__snapshots__/mcp/..., tests/__snapshots__/zod/...
Regenerated snapshots across 18 fixture files now include ListPetsResponseItem (union of pet variants with shared fields) and ListPetsResponse (array wrapper) for list endpoint responses. Variants include branded types and preprocess wrappers where applicable.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested labels

zod, bug

Suggested reviewers

  • melloware

Poem

🐰 Hops through media types with joy,
Regex patterns now deployed,
Charset handlers, trim and match,
JSON variants all catch,
Snapshots bloom from core delight!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title directly and clearly describes the main change: fixing Zod's handling of content-type headers with charset parameters, which is the core issue addressed in packages/zod/src/index.ts.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR updates the Zod generator’s media-type detection to correctly handle charset parameters (and other ;... parameters) and recognize more JSON-like media types, then updates generated snapshots and adds a regression test.

Changes:

  • Match JSON and multipart media types by normalizing away ; charset=... parameters and supporting application/*+json variants.
  • Add a comprehensive test covering request/response content types with charset and multipart encoding behavior.
  • Regenerate snapshots to reflect updated response schema generation (e.g., ListPetsResponseItem).

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/snapshots/zod/tags/pets.ts Snapshot updated to include ListPetsResponseItem and array response schema.
tests/snapshots/zod/split/endpoints.ts Snapshot updated for response item extraction and array response schema.
tests/snapshots/zod/schemas-false/endpoints.ts Snapshot updated for response item extraction and array response schema.
tests/snapshots/zod/preprocess/preprocess.ts Snapshot updated; response item schema now wrapped in zod.preprocess.
tests/snapshots/zod/petstore/endpoints.ts Snapshot updated to include ListPetsResponseItem and ListPetsResponse.
tests/snapshots/zod/petstore-tags-split/pets/pets.ts Snapshot updated to include response item extraction.
tests/snapshots/zod/branded-types/branded-types.ts Snapshot updated; response array uses .brand<'ListPetsResponse'>().
tests/snapshots/mcp/zod-schema-response/tool-schemas.zod.ts Snapshot updated to include response item extraction and array response schema.
tests/snapshots/mcp/single/tool-schemas.zod.ts Snapshot updated to include response item extraction and array response schema.
tests/snapshots/mcp/custom-server/tool-schemas.zod.ts Snapshot updated to include response item extraction and array response schema.
tests/snapshots/hono/zod-schema-response/endpoints.zod.ts Snapshot updated to include response item extraction and array response schema.
tests/snapshots/hono/petstore-tags/pets.zod.ts Snapshot updated to include response item extraction and array response schema.
tests/snapshots/hono/petstore-tags-with-handlers/pets.zod.ts Snapshot updated to include response item extraction and array response schema.
tests/snapshots/hono/petstore-tags-split/pets/pets.zod.ts Snapshot updated to include response item extraction and array response schema.
tests/snapshots/hono/petstore-tags-split-with-handlers/pets/pets.zod.ts Snapshot updated to include response item extraction and array response schema.
tests/snapshots/hono/petstore-split/endpoints.zod.ts Snapshot updated to include response item extraction and array response schema.
tests/snapshots/hono/petstore-split-with-handlers/endpoints.zod.ts Snapshot updated to include response item extraction and array response schema.
tests/snapshots/hono/petstore-single/endpoints.zod.ts Snapshot updated to include response item extraction and array response schema.
tests/snapshots/hono/endpoint-parameters/endpoints.zod.ts Snapshot updated to add generated response schemas and defaults for additional endpoints.
tests/snapshots/default/schemas-zod-only/endpoints.ts Snapshot updated to include response item extraction and array response schema.
packages/zod/src/zod.test.ts Adds regression test for charset-bearing media types and multipart encoding mapping.
packages/zod/src/index.ts Implements media type normalization/matching and extracts helper for matching.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/zod/src/index.ts
Comment on lines +1436 to +1440
const isMediaType =
(pattern: string) =>
([contentType]: [string, object]): boolean =>
new RegExp(pattern).test(contentType.split(';')[0].trim().toLowerCase());

Comment thread packages/zod/src/index.ts
Comment on lines +1436 to +1439
const isMediaType =
(pattern: string) =>
([contentType]: [string, object]): boolean =>
new RegExp(pattern).test(contentType.split(';')[0].trim().toLowerCase());
Comment on lines +49 to +83
export const ListPetsResponseItem = zod
.union([
zod
.union([
zod.object({
cuteness: zod.number(),
breed: zod.enum(['Labradoodle']),
}),
zod.object({
length: zod.number(),
breed: zod.enum(['Dachshund']),
}),
])
.and(
zod.object({
barksPerMinute: zod.number().optional(),
type: zod.enum(['dog']),
}),
),
zod.object({
petsRequested: zod.number().optional(),
type: zod.enum(['cat']),
}),
])
.and(
zod.object({
'@id': zod.string().optional(),
id: zod.number(),
name: zod.string(),
tag: zod.string().optional(),
email: zod.string().email().optional(),
callingCode: zod.enum(['+33', '+420']).optional(),
country: zod.enum(["People's Republic of China", 'Uruguay']).optional(),
}),
);

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/zod/src/zod.test.ts (1)

6279-6406: ⚡ Quick win

Add a focused application/*+json test case.

This new test locks charset handling, but it doesn’t explicitly assert vendor +json matching (for example application/vnd.api+json). Adding one small case here would directly protect the new regex behavior from regressions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/zod/src/zod.test.ts` around lines 6279 - 6406, Add a small focused
test that ensures vendor "+json" media types with charsets are matched by the
new regex: call generateZod (same pattern used in the existing "content type
with charset precision: comprehensive content type handling" test) with a schema
whose response content key is "application/vnd.api+json; charset=utf-8" (or
"application/ld+json; charset=utf-8") and assert the generated response Zod type
(e.g., UploadFormResponse from the diff) is produced as a zod.object; this
verifies generateZod's content-type matching logic handles application/*+json
with charsets correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/zod/src/zod.test.ts`:
- Around line 6279-6406: Add a small focused test that ensures vendor "+json"
media types with charsets are matched by the new regex: call generateZod (same
pattern used in the existing "content type with charset precision: comprehensive
content type handling" test) with a schema whose response content key is
"application/vnd.api+json; charset=utf-8" (or "application/ld+json;
charset=utf-8") and assert the generated response Zod type (e.g.,
UploadFormResponse from the diff) is produced as a zod.object; this verifies
generateZod's content-type matching logic handles application/*+json with
charsets correctly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b8c47035-7a20-4cf4-9382-f35a7ee66559

📥 Commits

Reviewing files that changed from the base of the PR and between f2b15fe and c913660.

📒 Files selected for processing (22)
  • packages/zod/src/index.ts
  • packages/zod/src/zod.test.ts
  • tests/__snapshots__/default/schemas-zod-only/endpoints.ts
  • tests/__snapshots__/hono/endpoint-parameters/endpoints.zod.ts
  • tests/__snapshots__/hono/petstore-single/endpoints.zod.ts
  • tests/__snapshots__/hono/petstore-split-with-handlers/endpoints.zod.ts
  • tests/__snapshots__/hono/petstore-split/endpoints.zod.ts
  • tests/__snapshots__/hono/petstore-tags-split-with-handlers/pets/pets.zod.ts
  • tests/__snapshots__/hono/petstore-tags-split/pets/pets.zod.ts
  • tests/__snapshots__/hono/petstore-tags-with-handlers/pets.zod.ts
  • tests/__snapshots__/hono/petstore-tags/pets.zod.ts
  • tests/__snapshots__/hono/zod-schema-response/endpoints.zod.ts
  • tests/__snapshots__/mcp/custom-server/tool-schemas.zod.ts
  • tests/__snapshots__/mcp/single/tool-schemas.zod.ts
  • tests/__snapshots__/mcp/zod-schema-response/tool-schemas.zod.ts
  • tests/__snapshots__/zod/branded-types/branded-types.ts
  • tests/__snapshots__/zod/petstore-tags-split/pets/pets.ts
  • tests/__snapshots__/zod/petstore/endpoints.ts
  • tests/__snapshots__/zod/preprocess/preprocess.ts
  • tests/__snapshots__/zod/schemas-false/endpoints.ts
  • tests/__snapshots__/zod/split/endpoints.ts
  • tests/__snapshots__/zod/tags/pets.ts

@melloware

Copy link
Copy Markdown
Collaborator

Thank you!

@melloware
melloware merged commit 61d5dfc into orval-labs:master May 24, 2026
6 checks passed
@pierre-isabel-bbc

Copy link
Copy Markdown

Thanks for the fix!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Zod: application/geo+json response schemas not being generated

4 participants