openapi-python-client icon indicating copy to clipboard operation
openapi-python-client copied to clipboard

feat: Support responses with multiple media types in `content`

Open nkrishnaswami opened this issue 5 months ago • 1 comments

This PR modifies openapi-python-client to recognize multiple media types in OpenAPI response objects and to differentially parse HTTP responses based on their Content-Type header values. (Today, it generates code for a single content media type of the ones it encounters in the OpenAPI document.) This is useful eg for modeling services where a load balancer can send a 429 with plain text but the service behind it might send one with a schematized JSON response type.

Feedback is welcome, especially on the overall approach.

This PR adds unit tests and one end-to-end test, the latter of which includes sample generated code in the end_to_end_tests/multiple-media-types-golden-record/ subdirectory.

To maintain backward compatibility and minimize impact on existing callers, unexpected response content types raise the existing UnexpectedStatus error, rather than introducing a new error class

This uses exact string matching to compare returned content types with the media types from the schema. This offers only a subset of the available OpenAPI functionality: this PR does not provide support for wildcards, case insensitivity, or parameters. To add proper range matching (wildcard) support, we'd need something like the logic in python-mimeparse

Uncovered diff lines:

  1. openapi_python_client/parser/openapi.py:204: This is a "belt-and-suspenders" check to avoid accessing an optional field if it is null. However, responses.py will not actually populate any MediaType instances with a null prop.
         for media_type in response.content:
             if not media_type.prop:  # pragma: no cover
                 continue
             endpoint.relative_imports |= media_type.prop.get_lazy_imports(prefix=models_relative_prefix)
             endpoint.relative_imports |= media_type.prop.get_imports(prefix=models_relative_prefix)
         endpoint.responses.append(response)

nkrishnaswami avatar Aug 01 '25 19:08 nkrishnaswami

C.f. #1248

nkrishnaswami avatar Nov 23 '25 00:11 nkrishnaswami