Skip to content

fix(validation): surface a skip for non-JSON content types that declare a schema (#254)#255

Merged
wadakatu merged 2 commits into
mainfrom
fix/non-json-schema-skip-issue-254
May 18, 2026
Merged

fix(validation): surface a skip for non-JSON content types that declare a schema (#254)#255
wadakatu merged 2 commits into
mainfrom
fix/non-json-schema-skip-issue-254

Conversation

@wadakatu
Copy link
Copy Markdown
Collaborator

Summary

When a non-JSON request/response Content-Type matched a spec media-type key
and that entry declared a schema, the body went unchecked (this engine only
evaluates JSON Schema) yet the run was still recorded as a clean success.
This surfaces such cases as Skipped with a skip reason on both the request
and response sides; non-JSON entries without a schema keep succeeding
silently as before.

Why

OpenAPI permits a schema on any media type, but the validation engine is
JSON-Schema-only and cannot evaluate a non-JSON one. The response side already
surfaced a Skipped outcome for the "spec declares only non-JSON content
types" case — but only when matchedContentType was null, so a non-JSON type
that matched a declared spec key bypassed that path and was reported as a
validated success. The request side had no skip surfacing at all. As a result
users could not tell that a non-JSON body's schema was never checked, and the
coverage report counted the endpoint as a clean pass — contrary to the tool's
"never show unvalidated as validated" principle.

Fixes #254.

Verification

Failing tests were added first (non-JSON media type with a schema), then the
fix. Tests that pinned the previous behaviour — most notably
ResponseValidationTest::non_json_endpoint_with_explicit_content_type_marks_validated,
which encoded the exact bug — were rewritten to assert the corrected Skipped
outcome and coverage row.

  • composer test passes (1796 tests)
  • composer stan passes
  • composer cs-check passes

Notes for reviewers

  • OpenApiValidationResult::skipped() gains an optional matchedContentType
    argument (BC-safe) so the response-side skip records coverage against the
    exact media-type row rather than the wildcard bucket.
  • RequestBodyValidator::validate() return type changes from string[] to a
    new @internal RequestBodyValidationResult DTO (errors + skipReason),
    mirroring the response-side ResponseBodyValidationResult. The body
    validator is now run behind an inlined RuntimeException boundary in
    OpenApiRequestValidator::validateBody() — same pattern as
    OpenApiResponseValidator::validateBody(), since the DTO return cannot flow
    through ValidatorErrorBoundary::safely().
  • Public orchestrator signatures (OpenApiRequestValidator::validate() /
    OpenApiResponseValidator::validate()) are unchanged.
  • docs/setup.md had a stale claim that isSkipped() is true "only for
    status-code skips" — corrected here alongside the behaviour change.

…re a schema (#254)

When a non-JSON Content-Type matched a spec media-type key and that
entry carried a `schema`, the body could not be validated by the JSON
Schema engine, yet the run was still recorded as a clean success.

Surface this as `Skipped` with a skip reason on both the request and
response sides so the gap is visible. Non-JSON entries without a
`schema` continue to succeed silently as before.
…nts (#254)

Add constructor guards to RequestBodyValidationResult and
ResponseBodyValidationResult that reject contradictory states via
InvalidArgumentException: a skipReason set together with errors, and on
the response side a skipReason set together with a null
matchedContentType. This follows the precedent of the
OpenApiValidationResult::failure([]) guard.

Close the test gaps raised in review:
- a non-JSON body skip must not mask a missing required response
  header error
- a request-side skip reason must be recorded in coverage
- skip on a wildcard (application/*) range match
- the DTO guards fire on contradictory input

Strengthen two existing tests that weakly pinned the old buggy
behavior with assertions for the new skip behavior.

Add a comment on non-array schema handling and fix a stale comment in
OpenApiResponseValidator after the DTO grew to three fields.
@wadakatu wadakatu merged commit 44169d4 into main May 18, 2026
16 checks passed
@wadakatu wadakatu deleted the fix/non-json-schema-skip-issue-254 branch May 18, 2026 09:50
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.

tech-debt(validation) — spec が宣言した非 JSON Content-Type のボディが診断なしで素通りする

1 participant