Skip to content

feat: add response body validation via validateResponse option#317

Merged
G4brym merged 2 commits into
mainfrom
feat/response-validation
Feb 26, 2026
Merged

feat: add response body validation via validateResponse option#317
G4brym merged 2 commits into
mainfrom
feat/response-validation

Conversation

@G4brym

@G4brym G4brym commented Feb 25, 2026

Copy link
Copy Markdown
Member

Summary

Closes #159

Adds a validateResponse router option that, when enabled, parses response bodies through their Zod response schema. This provides two key benefits:

  1. Strips unknown fields — prevents accidentally leaking sensitive data (e.g., password hashes, internal IDs) that aren't in the response schema
  2. Validates required fields — catches mismatches between declared response schema and actual return values at runtime

Usage

// Enable globally for all routes
const router = fromIttyRouter(AutoRouter(), { validateResponse: true });
// or
const router = fromHono(app, { validateResponse: true });

How it works

  • After handle() returns, the response is parsed through the Zod schema for the matching status code
  • Plain objects: parsed directly, unknown fields stripped
  • Response objects: JSON body is read, parsed, and the Response is reconstructed with the same status/headers
  • Non-JSON responses (HTML, text, etc.): passed through unchanged
  • No response schema defined: passed through unchanged (backward compatible)
  • Missing required fields: throws a ZodError (formatted as 400 by itty-router, raised as HTTPException by Hono)

Changes

  • src/types.ts: Added validateResponse?: boolean to RouterOptions and RouteOptions
  • src/openapi.ts: Forward the option to route instances
  • src/route.ts: Added getResponseSchema() and validateResponse() methods, called in execute() when the option is enabled
  • 7 integration tests covering: field stripping (plain objects and Response objects), passthrough when no schema, validation errors, default behavior unchanged, Hono integration

@github-actions

github-actions Bot commented Feb 25, 2026

Copy link
Copy Markdown
Contributor

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 94.56% 731 / 773
🔵 Statements 94.47% 753 / 797
🔵 Functions 91.61% 153 / 167
🔵 Branches 87.15% 441 / 506
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
src/exceptions.ts 100% 100% 100% 100%
src/openapi.ts 89.53% 85% 80.95% 89.41% 61, 249, 254-270, 350-368
src/route.ts 96.69% 91.02% 100% 98.19% 239, 245, 300, 350
Generated in workflow #666 for commit 4aa1d44 by the Vitest Coverage Report Action

@pkg-pr-new

pkg-pr-new Bot commented Feb 25, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/cloudflare/chanfana@317

commit: 4aa1d44

Add a validateResponse router option that parses response bodies through
their Zod schema. When enabled, unknown fields are stripped from JSON
responses and missing required fields trigger validation errors. Works
with both plain object returns and Response objects.
@G4brym G4brym force-pushed the feat/response-validation branch from c9bfec3 to 101ce6d Compare February 26, 2026 22:20
…andling, and docs

- Return 500 (not 400) for response validation failures via new
  ResponseValidationException (code 7013, isVisible: false)
- console.error full ZodError details for server-side debugging
- Isolate response validation in its own try/catch (no longer flows
  through handleError hook as a raw ZodError)
- Delete Content-Length/Transfer-Encoding headers when reconstructing
  Response objects after field stripping
- Clone Response before consuming body for defensive recovery
- Add 7 new tests: non-JSON passthrough, null responses, default schema
  fallback, unmatched status codes, Hono+Response, passthroughErrors
  interaction, Zod defaults on responses
- Update existing invalid-data tests to expect 500/7013
- Document validateResponse option in router options docs
- Document ResponseValidationException in error handling docs
- Expand changeset with usage examples and behavior details
@G4brym G4brym merged commit 39c89d2 into main Feb 26, 2026
8 checks passed
@G4brym G4brym deleted the feat/response-validation branch February 26, 2026 22:58
@github-actions github-actions Bot mentioned this pull request Feb 26, 2026
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.

Response body/format validation

1 participant