question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

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

See original GitHub issue

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

Issue Analytics

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

github_iconTop GitHub Comments

3reactions
davidraleighcommented, Aug 30, 2021

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

2reactions
zliebersbachcommented, Aug 3, 2021

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

Read more comments on GitHub >

github_iconTop Results From Across the Web

oneOf, anyOf, allOf, not - Swagger
OpenAPI 3.0 provides several keywords which you can use to combine schemas. You can use these keywords to create a complex schema, or...
Read more >
How to use OpenAPI "oneOf" property with openapi-generator ...
I have been battling to generate a PHP client for an API that heavily uses anyOf and oneOf. After some googling and finding...
Read more >
OpenAPI Definition & Online Tools | Open API Standards List
The following are small OpenAPI 3.0 examples to show different request types. ... do so with specific keywords (oneOf, anyOf, allOf, and not)...
Read more >
OpenAPI Specification v3.0.1 | Introduction, Definitions, & More
The discriminator attribute is legal only when using one of the composite keywords oneOf , anyOf , allOf . In OAS 3.0, a...
Read more >
Why You Need oneOf in Your OpenAPI Specifications - APIMatic
What is oneOf? According to OpenAPI Specification: “oneOf is simply a keyword defined by OpenAPI 3.0 which can be used to combine schemas.”...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found