Skip to content

Add strict_response_content_type option to ResponseValidation middleware - #478

Merged
geemus merged 1 commit into
interagent:masterfrom
whoward:wh/strict-content-types
Aug 14, 2026
Merged

Add strict_response_content_type option to ResponseValidation middleware#478
geemus merged 1 commit into
interagent:masterfrom
whoward:wh/strict-content-types

Conversation

@whoward

@whoward whoward commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Committee silently skips response body schema validation when the response Content-Type doesn't match any key declared in the OpenAPI spec's content map for that operation. This means a server returning application/vnd.api+json against a spec that only declares application/json passes validation without error. The new opt-in flag strict_response_content_type: false (default false for backwards compatibility) raises Committee::InvalidResponse in this case. The guard is skipped for responses with no content map at all (e.g. bare 204s), which continue to pass silently.

The check is implemented as a pre-guard in OperationWrapper#validate_response_params before handing off to openapi_parser's validate_response_body, since openapi_parser has no hook to express this policy without modifying the gem or repurposing the existing strict: flag. Status code lookup replicates openapi_parser's wildcard matching (4XX, default) via a private find_response_object_for_status helper. Content-Type params (e.g. charset=utf-8) are stripped via Rack::MediaType.type before matching, consistent with how validate_post_request_params handles request body content types.

This work implements #477

@geemus geemus left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Overall looks good to me, though it looks like our test coverage dropped below a threshold (you were unlucky in your timing maybe). That said, it would probably be good to unit test the find_response_object_for_status part as it is a bit involved. Could you look at fleshing that out a bit more (and if coverage is still insufficient, we can discuss other options/tweaks).

Thanks and apologies for my delay in reviewing.

@whoward
whoward force-pushed the wh/strict-content-types branch from 0d5391b to 0f5e144 Compare August 10, 2026 01:55
Committee silently skips response body schema validation when the response Content-Type
doesn't match any key declared in the OpenAPI spec's content map for that operation. This
means a server returning application/vnd.api+json against a spec that only declares
application/json passes validation without error. The new opt-in flag
strict_response_content_type: false (default false for backwards compatibility) raises
Committee::InvalidResponse in this case. The guard is skipped for responses with no
content map at all (e.g. bare 204s), which continue to pass silently.

The check is implemented as a pre-guard in OperationWrapper#validate_response_params
before handing off to openapi_parser's validate_response_body, since openapi_parser has
no hook to express this policy without modifying the gem or repurposing the existing
strict: flag. Status code lookup replicates openapi_parser's wildcard matching (4XX,
default) via a private find_response_object_for_status helper. Content-Type params
(e.g. charset=utf-8) are stripped via Rack::MediaType.type before matching, consistent
with how validate_post_request_params handles request body content types.
@whoward
whoward force-pushed the wh/strict-content-types branch from 0f5e144 to 5dbafa4 Compare August 10, 2026 03:08
@whoward

whoward commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

@geemus no worries! I believe I've fixed the coverage issue and have added unit tests covering find_response_object_for_status on it's own. since this is a private method unit testing required the use of send() - hopefully that's not an issue. Test coverage should now be 99.1%

@geemus

geemus commented Aug 14, 2026

Copy link
Copy Markdown
Member

LGTM, thanks!

@geemus
geemus merged commit 0c79077 into interagent:master Aug 14, 2026
9 checks passed
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.

2 participants