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.57k stars 6.52k forks source link

[BUG] OpenAPI.yaml generated returns strings without double quotes and "no" string is implicitly interpreted as boolean #3196

Open GuillaumeSmaha opened 5 years ago

GuillaumeSmaha commented 5 years ago

Bug Report Checklist

Description

openapi.yaml file generated in the project with {{{openapi-yaml}}} like https://github.com/OpenAPITools/openapi-generator/blob/20b8eff6e3dcec5dfe955b5dda1e4b84d8bdce44/modules/openapi-generator/src/main/resources/python-flask/openapi.mustache doesn't use double quotes around string values. Because in YAML specification, it seems value true/false, yes/no and on/off can be implicitly convert to boolean unless the value have double quotes. Here the code in PyYAML: https://github.com/yaml/pyyaml/blob/4c2e993321ad29a02a61c4818f3cef9229219003/lib3/yaml/resolver.py#L170-L175

Example: The yaml generated should return - "no" instead of - no to avoid implicit convertion.

openapi-generator version

4.0.3-beta It can be a regression because it was not present in swagger-codegen

OpenAPI declaration file content or url & Command line used for generation

I am using the online version to generate python-flask server with the following JSON openapi.quote.json.zip

{
  "host": "HOST",
  "info": {
    "description": "Car example",
    "title": "Car API",
    "version": "1.0.0"
  },
  "definitions": {
    "car": {
      "properties": {
        "name": {
          "description": "The name of the car.",
          "maxLength": 255,
          "type": "string"
        },
        "test": {
          "description": "Buggy enum: no becomes False",
          "enum": [
            "no",
            "great",
            "other"
          ],
          "type": "string"
        }
      },
      "required": [
        "name",
        "test"
      ]
    }
  },
  "paths": {
    "/v1/cars": {
      "post": {
        "parameters": [
          {
            "in": "body",
            "name": "body",
            "required": true,
            "schema": {
              "type": "array",
              "items": {
                "$ref": "#/definitions/car"
              }
            }
          }
        ],
        "consumes": [
          "application/json"
        ],
        "responses": {
          "200": {
            "description": "Successfully updated"
          }
        },
        "summary": "Add cars",
        "tags": [
          "Cars"
        ]
      }
    }
  },
  "schemes": [
    "https"
  ],
  "swagger": "2.0"
}
Steps to reproduce
curl -H "Content-type: application/json" -X POST --data-binary @openapi.quote.json http://api-latest-master.openapi-generator.tech/api/gen/servers/python-flask
curl http://api-latest-master.openapi-generator.tech/api/gen/download/298f2e1b-447c-41c1-841f-6544899e3043 -o server.zip
unzip server.zip
cd python-flask-server
cat car_api/openapi/openapi.yaml
python3 -m venv venv
. ./venv/bin/activate
pip install -r requirements.txt
# Run the server
python3 -m car_api

# In other terminal
# "great" value should work and it works: returns "do some magic!"
curl http://localhost:8080/v1/cars -XPOST -H 'Content-type: application/json' -d '[{"name": "car name", "test": "great"}]'

# "fail" value should fail and it fails as expected
curl http://localhost:8080/v1/cars -XPOST -H 'Content-type: application/json' -d '[{"name": "car name", "test": "fail"}]'

# "no" value should work and it fails: returns "detail": "'no' is not one of [False, 'great', 'other']",
curl http://localhost:8080/v1/cars -XPOST -H 'Content-type: application/json' -d '[{"name": "car name", "test": "no"}]'

# Add doubles quotes:
sed -i 's/- \(yes\|Yes\|YES\|no\|No\|NO\|true\|True\|TRUE\|false\|False\|FALSE\|on\|On\|ON\|off\|Off\|OFF\)$/- "\1"/g' car_api/openapi/openapi.yaml

# Run the server with the update applied
python3 -m car_api

# In other terminal
# "no" value should work and it works: "do some magic!"
curl http://localhost:8080/v1/cars -XPOST -H 'Content-type: application/json' -d '[{"name": "car name", "test": "no"}]'

Generated file by openapi generator:

openapi: 3.0.1
info:
  description: Car example
  title: Car API
  version: 1.0.0
servers:
- url: https://HOST/
paths:
  /v1/cars:
    post:
      operationId: v1_cars_post
      requestBody:
        content:
          application/json:
            schema:
              items:
                $ref: '#/components/schemas/car'
              type: array
        required: true
      responses:
        200:
          content: {}
          description: Successfully updated
      summary: Add cars
      tags:
      - Cars
      x-codegen-request-body-name: body
      x-openapi-router-controller: car_api.controllers.cars_controller
components:
  schemas:
    car:
      properties:
        name:
          description: The name of the car.
          maxLength: 255
          type: string
        test:
          description: 'Buggy enum: no becomes False'
          enum:
          - no
          - great
          - other
          type: string
      required:
      - name
      - test
      type: object
Related issues/PRs

Maybe the same error in https://github.com/OpenAPITools/openapi-generator/issues/2870

Suggest a fix

Add double quotes ?

GuillaumeSmaha commented 5 years ago

I also tried using a yaml file where I explicitly use double quotes around no. See the following file (I re-used the generated file and just add double quotes):

openapi: 3.0.1
info:
  description: Car example
  title: Car API
  version: 1.0.0
servers:
- url: https://HOST/
paths:
  /v1/cars:
    post:
      operationId: v1_cars_post
      requestBody:
        content:
          application/json:
            schema:
              items:
                $ref: '#/components/schemas/car'
              type: array
        required: true
      responses:
        200:
          content: {}
          description: Successfully updated
      summary: Add cars
      tags:
      - Cars
      x-codegen-request-body-name: body
      x-openapi-router-controller: openapi_server.controllers.cars_controller
components:
  schemas:
    car:
      properties:
        name:
          description: The name of the car.
          maxLength: 255
          type: string
        test:
          description: 'Buggy enum: no becomes False'
          enum:
          - "no"
          - great
          - other
          type: string
      required:
      - name
      - test
      type: object

Generated file:

openapi: 3.0.1
info:
  description: Car example
  title: Car API
  version: 1.0.0
servers:
- url: https://HOST/
paths:
  /v1/cars:
    post:
      operationId: v1_cars_post
      requestBody:
        content:
          application/json:
            schema:
              items:
                $ref: '#/components/schemas/car'
              type: array
        required: true
      responses:
        200:
          content: {}
          description: Successfully updated
      summary: Add cars
      tags:
      - Cars
      x-codegen-request-body-name: body
      x-openapi-router-controller: openapi_server.controllers.cars_controller
components:
  schemas:
    car:
      properties:
        name:
          description: The name of the car.
          maxLength: 255
          type: string
        test:
          description: 'Buggy enum: no becomes False'
          enum:
          - no
          - great
          - other
          type: string
      required:
      - name
      - test
      type: object

diff:

--- openapi.yaml    2019-06-27 18:22:18.785663477 -0400
+++ server/openapi_server/openapi/openapi.yaml  2019-06-27 18:22:38.901792481 -0400
@@ -37,7 +37,7 @@
         test:
           description: 'Buggy enum: no becomes False'
           enum:
-          - "no"
+          - no
           - great
           - other
           type: string
GuillaumeSmaha commented 5 years ago

Ok. I found that openapi-generator are using the new tool v3 provided by swagger-codegen import io.swagger.v3.core.util.Yaml;: https://github.com/OpenAPITools/openapi-generator/blob/046db19a8590f3557ae1e04be75792bbeb39cb69/modules/openapi-generator/src/main/java/org/openapitools/codegen/serializer/SerializerUtils.java#L22-L26

That why there is a difference with swagger-codegen because they still use the old version import io.swagger.util.Yaml;: https://github.com/swagger-api/swagger-codegen/blob/2a9043aea547479ed5123c7150403e5f9293c2af/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/FlaskConnexionCodegen.java#L384

But this is mainly due to the usage of the option YAMLGenerator.Feature.MINIMIZE_QUOTES on the v3: https://github.com/swagger-api/swagger-core/blob/5e61d6a1b3b0251869be71cf2913210dfa870276/modules/swagger-core/src/main/java/io/swagger/v3/core/util/ObjectMapperFactory.java#L65

I also found this issue on FastXML/jackson-dataformats-text: https://github.com/FasterXML/jackson-dataformats-text/issues/129 where it seems there is something weird in the formatting for Yaml spec 1.1 because the dependency for FastXML is SnakeYAML https://bitbucket.org/asomov/snakeyaml/ which is a formatter for Yaml 1.1 And Yaml 1.1 allows to implicitly convert some string to boolean whereas Yaml 1.2 don't. But Yaml 1.1 should protect string looking like a boolean to avoid implicit conversion.


I think FasterXML/jackson-dataformats-text needs a fix to protect the values listed in https://yaml.org/type/bool.html. I created PRs to fix this in the lib https://github.com/FasterXML/jackson-dataformats-text/pull/137 and https://github.com/FasterXML/jackson-dataformats-text/pull/138 But it can take time before this PR will be merged and the upgrade will be done in OpenAPI generator. So, my proposition is to remove the option MINIMIZE_QUOTES or to revert to import io.swagger.util.Yaml; if the first solution is not possible.

jimschubert commented 4 years ago

related: #4365

GuillaumeSmaha commented 4 years ago

PR for https://github.com/FasterXML/jackson-dataformats-text is merged, the fix is only available in a new release but it implies a lot of change with the fix.

laguiar commented 3 years ago

Hey folks, sorry to revive an old issue here, but since it’s Open, it might be the right place.

is there any fix already available for this string quotes problem?

I face the same problem for dates (YYYY-MM-DD) and for phone numbers that actually starts with the plus sign (+00 E.164 format).