OpenAPITools / openapi-generator

OpenAPI Generator allows generation of API client libraries (SDK generation), server stubs, documentation and configuration automatically given an OpenAPI Spec (v2, v3)
https://openapi-generator.tech
Apache License 2.0
21.69k stars 6.55k forks source link

[BUG] [DART] Invalid dart file generated for inline schema models (ValidationError/LocationInner) #13302

Open pierrecorsini opened 2 years ago

pierrecorsini commented 2 years ago

Bug Report Checklist

Description

image

openapi-generator version

openapi-generator-cli-7.0.0-20220719.043604-2.ja

OpenAPI declaration file content or url

http://127.0.0.1:8000/openapi.json ``` { "openapi": "3.0.2", "info": { "title": "FastAPI", "version": "0.1.0" }, "paths": { "/": { "get": { "summary": "Root", "operationId": "root__get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } } } } }, "/task": { "get": { "summary": "Gat Task", "operationId": "gat_task_task_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } } } }, "put": { "summary": "Add Task", "operationId": "add_task_task_put", "requestBody": { "content": { "application/json": { "schema": { "title": "Task", "required": [ "id", "name" ], "type": "object", "properties": { "id": { "title": "Id", "type": "string" }, "name": { "title": "Name", "type": "string" }, "done": { "title": "Done", "type": "boolean", "default": false } } } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "title": "HTTPValidationError", "type": "object", "properties": { "detail": { "title": "Detail", "type": "array", "items": { "title": "ValidationError", "required": [ "loc", "msg", "type" ], "type": "object", "properties": { "loc": { "title": "Location", "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "integer" } ] } }, "msg": { "title": "Message", "type": "string" }, "type": { "title": "Error Type", "type": "string" } } } } } } } } } } } } }, "components": { "schemas": { "HTTPValidationError": { "title": "HTTPValidationError", "type": "object", "properties": { "detail": { "title": "Detail", "type": "array", "items": { "title": "ValidationError", "required": [ "loc", "msg", "type" ], "type": "object", "properties": { "loc": { "title": "Location", "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "integer" } ] } }, "msg": { "title": "Message", "type": "string" }, "type": { "title": "Error Type", "type": "string" } } } } } }, "Task": { "title": "Task", "required": [ "id", "name" ], "type": "object", "properties": { "id": { "title": "Id", "type": "string" }, "name": { "title": "Name", "type": "string" }, "done": { "title": "Done", "type": "boolean", "default": false } } }, "ValidationError": { "title": "ValidationError", "required": [ "loc", "msg", "type" ], "type": "object", "properties": { "loc": { "title": "Location", "type": "array", "items": { "anyOf": [ { "type": "string" }, { "type": "integer" } ] } }, "msg": { "title": "Message", "type": "string" }, "type": { "title": "Error Type", "type": "string" } } } } } } ```

Generation Details

Generate dart.

Steps to reproduce

  1. Get the json file.
  2. java -jar openapi-generator-cli-7.0.0-20220719.043604-2.jar generate -i http://127.0.0.1:8000/openapi.json -g dart -o openapi

Related issues/PRs

/

Suggest a fix

Not able to identify a fix, shema seems valid, this could be an issue with inline/embeded shema models ?

clotodex commented 1 year ago

Same issue - using built_value works, so it is not an issue with the schema or settings.

clotodex commented 1 year ago

@pc-robelbois did you find a workaround for now?

DonFortes commented 1 year ago

Hello! Was it possible to fix the problem? I have the same issue

Tand0 commented 1 year ago

Hello! me too!

maurovitale commented 11 months ago

Hello, I'm using the following open api json structure:

{
  "openapi": "3.1.0",
  "info": {
    "title": "FastAPI",
    "version": "0.1.0"
  },
  "paths": {
    "/token": {
      "post": {
        "summary": "Login For Access Token",
        "operationId": "login_for_access_token_token_post",
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/Body_login_for_access_token_token_post"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Token"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/users/me/": {
      "get": {
        "summary": "Read Users Me",
        "operationId": "read_users_me_users_me__get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          }
        },
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ]
      }
    },
    "/users/me/items/": {
      "get": {
        "summary": "Read Own Items",
        "operationId": "read_own_items_users_me_items__get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          }
        },
        "security": [
          {
            "OAuth2PasswordBearer": []
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "Body_login_for_access_token_token_post": {
        "properties": {
          "grant_type": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "password"
              },
              {
                "type": "null"
              }
            ],
            "title": "Grant Type"
          },
          "username": {
            "type": "string",
            "title": "Username"
          },
          "password": {
            "type": "string",
            "title": "Password"
          },
          "scope": {
            "type": "string",
            "title": "Scope",
            "default": ""
          },
          "client_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Client Id"
          },
          "client_secret": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Client Secret"
          }
        },
        "type": "object",
        "required": [
          "username",
          "password"
        ],
        "title": "Body_login_for_access_token_token_post"
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "Token": {
        "properties": {
          "access_token": {
            "type": "string",
            "title": "Access Token"
          },
          "token_type": {
            "type": "string",
            "title": "Token Type"
          }
        },
        "type": "object",
        "required": [
          "access_token",
          "token_type"
        ],
        "title": "Token"
      },
      "User": {
        "properties": {
          "username": {
            "type": "string",
            "title": "Username"
          },
          "email": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Email"
          },
          "full_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Full Name"
          },
          "disabled": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Disabled"
          }
        },
        "type": "object",
        "required": [
          "username"
        ],
        "title": "User"
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      }
    },
    "securitySchemes": {
      "OAuth2PasswordBearer": {
        "type": "oauth2",
        "flows": {
          "password": {
            "scopes": {},
            "tokenUrl": "token"
          }
        }
      }
    }
  }
}

the prompt that I'm using to generate the dart client (you can find the template in https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator/src/main/resources/dart2) project is:

openapi-generator generate -i /path_to/openapi.json -g dart -o /path_to/dart_client/

As output I'm having the same problem reported by @pierrecorsini :

validation_error

Are there already any solutions to solve this problem? Thanks,

filipposantovito commented 11 months ago

hello. I was able to replicate this bug. the offending model is:

      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      }

in particular the problem arises for the "loc" object:

          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          }

the associated dart class is generated using this template which uses {{#vars}}{{/vars}}. This prevents the inner dart code to be generated.

a working implementation for this case can be found in this python template that uses {{#anyOf}}{{/anyOf}} to produce valid python code.

A possible solution could be creating a native_class_anyof.mustache that correctly manage this particular case.

openapi-generator generate -i /path_to/openapi.json -g dart -o /path_to/dart_client/

the openapi.json and validation_error_loc_inner.dart are attached. files.zip

Tand0 commented 11 months ago

in particular the problem arises for the "loc" object:

Great discovery! I find a workaround was able to avoid the error by following .

$ python openapi_changer.py http://192.168.1.1:3002/openapi.json
$ openapi-generator-cli generate -g dart -i openapi.json -o dart_client

def main(): with requests.Session() as session: result = session.get(sys.argv[1]) if (result.status_code != 200): print("ERROR: status_code=" + result.status_code) return data = json.loads(result.text) if (("components" in data) and ("schemas" in data["components"]) and ("ValidationError" in data["components"]["schemas"]) and ("properties" in data["components"]["schemas"]["ValidationError"]) and ("loc" in data["components"]["schemas"]["ValidationError"]["properties"]) and ("items" in data["components"]["schemas"]["ValidationError"]["properties"]["loc"])): data["components"]["schemas"]["ValidationError"]["properties"]["loc"]["items"] = {"type": "string"} with open('./openapi.json', 'w') as f: json.dump(data, f, indent=2)

if name == "main": main()


Enjoy!
garricklw commented 11 months ago

I'm running into this issue with many other classes that are being generated by the python FastAPI library, in addition to the ValidationError issue other people are running into.

For example, the "allowed_variable_values" inner class is being generated with a missing constructor field and non-working .dart code:

Survey:
  properties:
    id:
      type: string
      title: Id
    name:
      type: string
      title: Name
    allowed_variable_values:
      additionalProperties:
        items:
          anyOf:
          - type: number
          - type: integer
          - type: string
        type: array
        uniqueItems: true
      type: object
      title: Allowed Variable Values
    variable_to_value_alias_to_original:
      additionalProperties:
        additionalProperties:
          anyOf:
          - type: number
          - type: integer
          - type: string
        type: object
      type: object
      title: Variable To Value Alias To Original
    demographic_variable_ids:
      items:
        type: string
      type: array
      title: Demographic Variable Ids
    sociocultural_dimension_calculation:
      $ref: '#/components/schemas/LinearCoefficientCalculation'
  type: object
  required:
  - id
  - name
  - allowed_variable_values
  - variable_to_value_alias_to_original
  - demographic_variable_ids
  - sociocultural_dimension_calculation
  title: Survey
  example:
    allowed_variable_values:
      var_1:
      - 0
      - 1
      - 2
      - 3
      var_2:
      - 0
      - 0.5
      - 1
      var_3:
      - a
      - b
      - c
    demographic_variable_ids:
    - var_2
    id: test_survey
    name: Test Survey
    sociocultural_dimension_calculation:
      coefficients:
        Need Safety:
          var_1: 1.5
          var_2: 2.0
    variable_to_value_alias_to_original:
      var_1:
        '1': 1
        '2': 2
        '3': 3
        'None': 0
      var_2:
        A Lot: 1
        Not at All: 0
        Somewhat: 0.5
      var_3:
        apples: a
        bananas: b
        cantaloupe: c
filipposantovito commented 11 months ago

@garricklw sure. It's the same problem for a different class. The dart generator is missing an #anyOf class generator.

garricklw commented 11 months ago

@filipposantovito ah, ok I wasn't picking that up, thanks for clarifying.

gawi151 commented 2 months ago

Any updates on the fix for this problem? The problem is related to anyOf which in result should generate some kind of composite or union class.

Union like types are supported in Dart3 with sealed class would be nice to see it here.