openapi-generators / openapi-generators/openapi-python-client

Generation for multiple content types for a single endpoint fails when content types expect identical models

Open
#1,276 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
2k
Forks
293
Avg merge
34m
Merged PRs (30d)
1

Description

Describe the bug
Support for multiple content types for a single endpoint was added in #453 / #822. However, the implemented fix generates non-functional code if the content types expect the same model. For instance, take this Api Spec snippet:

paths./api/dns/add/...
requestBody:
  content:
    application/json:
      schema:
        $ref: '#/components/schemas/DnsCreate'
    application/x-www-form-urlencoded:
      schema:
        $ref: '#/components/schemas/DnsCreate'
    multipart/form-data:
      schema:
        $ref: '#/components/schemas/DnsCreate'
  required: true

...
components.schemas...:

DnsCreate:
  type: object
  properties:
    name:
      type: string
    dns_type:
      oneOf:
      - $ref: '#/components/schemas/DnsTypeEnum'
      - $ref: '#/components/schemas/BlankEnum'
    content:
      type: string
    ttl:
      type: integer
      maximum: 2147483647
      minimum: -2147483648
      nullable: true
  required:
  - content
  - dns_type
  - name

All 3 content types expect the same content type: DnsCreate. However, this generates this Python code:

def _get_kwargs(
    *,
    body: Union[
        DnsCreate,
        DnsCreate,
        DnsCreate,
    ],
) -> dict[str, Any]:
    headers: dict[str, Any] = {}

    _kwargs: dict[str, Any] = {
        "method": "post",
        "url": "/api/dns/add/",
    }

    if isinstance(body, DnsCreate):
        _kwargs["json"] = body.to_dict()

        headers["Content-Type"] = "application/json"
    if isinstance(body, DnsCreate):
        _kwargs["data"] = body.to_dict()

        headers["Content-Type"] = "application/x-www-form-urlencoded"
    if isinstance(body, DnsCreate):
        _kwargs["files"] = body.to_multipart()

        headers["Content-Type"] = "multipart/form-data"

    _kwargs["headers"] = headers
    return _kwargs

This results in all requests made to this endpoint being treated as multipart form data, and it is impossible to make a JSON or form-urlencoded request.

Desktop (please complete the following information):

  • Python Version: 3.12.3
  • openapi-python-client version: 0.25.0

Additional context
While it may seem odd to support 3 different content types for the same endpoint, this specification has the advantage of making Django Rest Framework's interactive API support form uploads (instead of requiring you to manually edit JSON). While I'm sure this is a more niche problem, I think we can all agree that this is problematic code generation. While I haven't contributed to this repo, perhaps supporting an additional content type parameter is the solution (rather than relying on isinstance calls).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing generation with the OpenAPI snippet in the issue and inspect the generated endpoint _get_kwargs function. Trace how identical models are associated with each request content type; done when JSON, form-urlencoded, and multipart requests remain selectable instead of being overwritten by the final branch.

Written by the indexing model from the issue text.

Assessment

Tech stack
openapi, python
Domain
api, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.