Skip to content

feat: content type handling customization#2449

Open
mromaszewicz wants to merge 1 commit into
oapi-codegen:mainfrom
mromaszewicz:feat/content-type-matching
Open

feat: content type handling customization#2449
mromaszewicz wants to merge 1 commit into
oapi-codegen:mainfrom
mromaszewicz:feat/content-type-matching

Conversation

@mromaszewicz

Copy link
Copy Markdown
Member

Partially addresses #2368.

Add an output-options.content-types setting: a map of short names (the tag spliced into generated type names, e.g. the JSON in FindPetsJSONRequestBody) to lists of regex patterns matched against request/response media types. Matching media types get models generated and named with the short name, so e.g. application/vnd.mycompany.v1+json can produce FindPetsV1RequestBody instead of a name derived from the media type.

User entries are merged on top of the built-in defaults (JSON, Formdata, Multipart, Text) by key replacement; an empty pattern list disables a key. A media type matching patterns under two different short names is a generation-time error. Vendored +json naming and the client-side YAML/XML/HAL handling remain media-type-derived fallbacks, so an unset mapping produces identical output to before.

To keep custom names from changing behavior, templates now branch on media-type-derived methods (IsFormdata/IsMultipart/IsText/IsSupported) instead of comparing NameTag strings, so wire-level handling (marshaling, binding) always follows the media type rather than the name.

@mromaszewicz
mromaszewicz requested a review from a team as a code owner July 10, 2026 17:23
@mromaszewicz mromaszewicz added enhancement New feature or request notable changes Used for release notes to highlight these more highly labels Jul 10, 2026
@greptile-apps

greptile-apps Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds output-options.content-types, a map from short names (e.g. V1, CSV) to regex patterns matched against request/response media types. Matched types use the short name in generated identifiers instead of the default derivation, and any matched media type gets models generated even if it isn't a built-in type. Templates are refactored to branch on media-type-derived predicate methods (IsFormdata, IsMultipart, IsText) rather than comparing NameTag strings, so wire-level behavior is always dictated by the content type itself.

  • Adds ContentTypes map[string][]string to OutputOptions with compile-time regex validation, JSON schema update, and docs update.
  • Introduces contentTypeNameTags with TagFor, merged defaults, and generation-time ambiguity detection; all 11 strict-server backend templates are updated to use method predicates.
  • Adds an integration test leaf at internal/test/options/content_types/ with generated output, unit tests, and a spec covering both vendored-JSON renaming and model-only (CSV) mapping.

Confidence Score: 5/5

The change is safe to merge; it adds an opt-in output option that leaves all existing generated output identical when the option is unset.

No existing behaviour changes for specs that don't set content-types. The refactor of NameTag-string comparisons to media-type-derived predicate methods is mechanically correct across all eleven backend templates, and the unit + integration tests validate both the renaming and model-generation paths.

No files require special attention. The JSON schema property-names gap in configuration-schema.json is cosmetic — it only affects IDE feedback, not runtime behaviour.

Important Files Changed

Filename Overview
pkg/codegen/configuration.go Adds ContentTypes field to OutputOptions, compileContentTypeNameTags with validation and sorting, and compile-time validation in Validate(). Defaults and regex compilation look correct.
pkg/codegen/operations.go Rewrites GenerateBodyDefinitions and GenerateResponseDefinitions to route through activeContentTypeNameTags().TagFor() before falling back to vendored-JSON derivation. Adds IsFormdata, IsMultipart, IsText, HasModel predicates. The IsSupported semantic change (NameTag→media-type check) is consistent with existing logic.
pkg/codegen/content_types_test.go Unit tests cover: short-name renaming, default-unchanged baseline, built-in rename with disambiguation, unsupported-type model generation, ambiguity error, and validation. Coverage is thorough.
internal/test/options/content_types/content_types.gen.go Generated output looks correct: V1-mapped vendored JSON gets typed request/response/strict types; CSV-mapped body generates model alias but strict server uses io.Reader as documented.
configuration-schema.json Adds content-types object property. The object's additionalProperties is correctly typed but the property names are not constrained to the Go-identifier pattern enforced at runtime.
pkg/codegen/templates/strict/strict-interface.tmpl All eq .NameTag "Multipart"/"Text"/"Formdata" comparisons replaced with method predicates. Logic is equivalent for all pre-existing media types; new custom types correctly fall to io.Reader.
internal/test/options/content_types/content_types_test.go Integration tests exercise compile-time type assertions, client V1-response parsing, CSV raw-body behavior, and strict CSV response streaming. Adequate coverage for the new test leaf.

Reviews (2): Last reviewed commit: "feat: content type handling customizatio..." | Re-trigger Greptile

Comment thread pkg/codegen/content_types_test.go
Partially addresses oapi-codegen#2368.

Add an output-options.content-types setting: a map of short names (the
tag spliced into generated type names, e.g. the JSON in
FindPetsJSONRequestBody) to lists of regex patterns matched against
request/response media types. Matching media types get models generated
and named with the short name, so e.g. application/vnd.mycompany.v1+json
can produce FindPetsV1RequestBody instead of a name derived from the
media type.

User entries are merged on top of the built-in defaults (JSON, Formdata,
Multipart, Text) by key replacement; an empty pattern list disables a
key. A media type matching patterns under two different short names is a
generation-time error. Vendored +json naming and the client-side
YAML/XML/HAL handling remain media-type-derived fallbacks, so an unset
mapping produces identical output to before.

To keep custom names from changing behavior, templates now branch on
media-type-derived methods (IsFormdata/IsMultipart/IsText/IsSupported)
instead of comparing NameTag strings, so wire-level handling (marshaling,
binding) always follows the media type rather than the name.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mromaszewicz
mromaszewicz force-pushed the feat/content-type-matching branch from 452080c to d24e195 Compare July 10, 2026 23:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request notable changes Used for release notes to highlight these more highly

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant