openapi-generator: [BUG][PYTHON] Using Openapi 3.0 Inheritance/Polymorphism keywords (allOf, anyOf, oneOf) causes generation of UNKNOWNBASETYPE model.

Bug Report Checklist

  • [y] Have you provided a full/minimal spec to reproduce the issue?
  • [y] Have you validated the input using an OpenAPI validator (example)?
  • [y] Have you tested with the latest master to confirm the issue still exists?
  • [y] Have you searched for related issues/PRs?
  • [y] What’s the actual output vs expected output?
  • [maybe ] [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description

Can’t use allof, anyof, or oneof keywords in request body → Will result in generating “UNKNOWNBASETYPE” which makes that client endpoint unusable. This is specific to Openapi 3.0. In Openapi 2.0 (swagger 2.0) one could get away with using “produces” and “consumes” (kubernetes api uses that) in POST requests. With Openapi 3.0, that has been replaced with requestBody and the use of the inheritance keywords (allOf, anyOf, oneOf). This problem also doesn’t seem specific to Python.

The following spec causes the issue:

OpenAPI declaration file content or url
openapi: 3.0.0
info:
  title: Sample API
  version: '2.0'
paths:
  /v2/projects:
    post:
      operationId: create_project
      summary: Create a Project
      description: 'To create a project, send a POST request to `/v2/projects`.'
      tags:
        - Projects
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/project_base'
              required:
              - name
              - purpose
      responses:
        '200':
          description: OK
components:
  schemas:
    project_base:
      type: object
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
          example: 4e1bfbc3
          description: The unique universal identifier of this project.
        name:
          type: string
          maxLength: 175
          example: my-web-api
          description: >-
            The human-readable name for the project. The maximum length is 175
            characters and the name must be unique.
        description:
          type: string
          maxLength: 255
          example: My website API
          description: >-
            The description of the project. The maximum length is 255
            characters.
        purpose:
          type: string
          maxLength: 255
          example: Service or API
Generation Details

Generates a client that imports: from openapi_client.model.unknownbasetype import UNKNOWNBASETYPE and uses it in place of the schema described in requestbody (project_base).

If you rework the POST request as such to remove the use of allOf, you are able to create a POST request but you lose the ability to specify which properties are required for that specific endpoint:

paths:
  /v2/projects:
    post:
      operationId: create_project
      summary: Create a Project
      description: 'To create a project, send a POST request to `/v2/projects`.'
      tags:
        - Projects
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/project_base'
      responses:
        '200':
          description: OK

^This will generate the expected import statements in the client: from openapi_client.model.project_base import ProjectBase

…but you lose the ability to specify which inherited properties are required for that specific endpoint). Also, if you were using oneOf or anyOf, I don’t think you’d be able to maintain their behavior with this workaround. I’ve seen people suggest creating a specific model for each endpoint and specify the required properties there, but that will cause the spec to be super clunky and generate weird model names.

Steps to reproduce

Create a file with the following spec:

openapi: 3.0.0
info:
  title: Sample API
  version: '2.0'
paths:
  /v2/projects:
    post:
      operationId: create_project
      summary: Create a Project
      description: 'To create a project, send a POST request to `/v2/projects`.'
      tags:
        - Projects
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/project_base'
              required:
              - name
              - purpose
      responses:
        '200':
          description: OK
components:
  schemas:
    project_base:
      type: object
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
          example: 4e1bfbc3
          description: The unique universal identifier of this project.
        name:
          type: string
          maxLength: 175
          example: my-web-api
          description: >-
            The human-readable name for the project. The maximum length is 175
            characters and the name must be unique.
        description:
          type: string
          maxLength: 255
          example: My website API
          description: >-
            The description of the project. The maximum length is 255
            characters.
        purpose:
          type: string
          maxLength: 255
          example: Service or API

run the following:

docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli generate -i/local/projects_allof.yaml -g python -o /local/last-try

Inspect the openapi_client/api/projects_api.py file and see if UNKNOWNBASETYPE is imported and used.

Related issues/PRs

This problem has been described in many issues: #2892 #5903 #7256 #7339. Also not specific to just Python.

openapi-generator version

Openapi 5.0.1, also used the latest master via docker

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 13
  • Comments: 15 (5 by maintainers)

Most upvoted comments

@stonecharioteer if you have the opportunity use protobuf + gRPC instead.

lol this issue seems to be in literally every single generator… not a very good look for a “spec-compliant” program!

Also happening in ruby