Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
5 of 6 tasks
GuillaumeSmaha opened this issue Jun 21, 2019 · 5 comments

Comments

@GuillaumeSmaha
Copy link
Contributor

GuillaumeSmaha commented Jun 21, 2019

Bug Report Checklist

  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator (example)?
  • What's the version of OpenAPI Generator used?
  • Have you search for related issues/PRs?
  • What's the actual output vs expected output?
  • [Optional] Bounty to sponsor the fix (example)
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 #2870

Suggest a fix

Add double quotes ?

@GuillaumeSmaha
Copy link
Contributor Author

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
Copy link
Contributor Author

GuillaumeSmaha commented Jun 28, 2019

Ok. I found that openapi-generator are using the new tool v3 provided by swagger-codegen import io.swagger.v3.core.util.Yaml;:

return Yaml.mapper()
.registerModule(module)
.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
.writeValueAsString(openAPI)
.replace("\r\n", "\n");

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: FasterXML/jackson-dataformats-text#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 FasterXML/jackson-dataformats-text#137 and FasterXML/jackson-dataformats-text#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.

GuillaumeSmaha added a commit to GuillaumeSmaha/openapi-generator that referenced this issue Jun 28, 2019
 quotes around string value and fix compatibility with parser using yaml 1.1.

Fix OpenAPITools#3196

In spec 1.1, some words without quotes can be implicitly converted to
 a boolean like "yes" or "on" (See https://yaml.org/type/bool.html)
In v3.core.util.Yaml with MINIMIZE_QUOTES enabled, the formatter created
 a YAML but forget to protect some words.

PRs are created to fix this in the formatter:
 - FasterXML/jackson-dataformats-text#137
 - FasterXML/jackson-dataformats-text#138

Until the PRs will be merged and released, this patch fix it by
re-adding quotes.
@jimschubert
Copy link
Member

related: #4365

@GuillaumeSmaha
Copy link
Contributor Author

GuillaumeSmaha commented Apr 15, 2020

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
Copy link

laguiar commented Sep 30, 2021

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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants