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

Use io.swagger.util.Yaml instead of io.swagger.v3.core.util.Yaml to add quotes around string value and fix compatibility with parser using yaml 1.1. #3237

Conversation

GuillaumeSmaha
Copy link
Contributor

PR checklist

  • Read the contribution guidelines.
  • Ran the shell script under ./bin/ to update Petstore sample so that CIs can verify the change. (For instance, only need to run ./bin/{LANG}-petstore.sh, ./bin/openapi3/{LANG}-petstore.sh if updating the {LANG} (e.g. php, ruby, python, etc) code generator or {LANG} client's mustache templates). Windows batch files can be found in .\bin\windows\. If contributing template-only or documentation-only changes which will change sample output, be sure to build the project first.
  • Filed the PR against the correct branch: master, 4.1.x, 5.0.x. Default: master.
  • Copied the technical committee to review the pull request if your PR is targeting a particular programming language.

Description of the PR

Fix #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:

Until the PRs will be merged and released, this patch fix it by
re-adding quotes.

@GuillaumeSmaha
Copy link
Contributor Author

Committee: @OpenAPITools/generator-core-team

 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.
@GuillaumeSmaha GuillaumeSmaha force-pushed the revert_minimize_quotes_for_compatibility branch from ee5d319 to 28de27a Compare June 28, 2019 05:42
@GuillaumeSmaha
Copy link
Contributor Author

Here you can see in this failed build, the content generated without the quotes:
https://circleci.com/gh/OpenAPITools/openapi-generator/7374

components:
  schemas:
    SomeObject:
      description: An Obj
      properties:
        id:
          type: string
        stringBoolean:
          default: "true"
          type: string
        switch:
          default: on
          type: string
        valid:
          default: true
          type: boolean

"true" is correctly managed but not on

@jmini
Copy link
Member

jmini commented Jun 28, 2019

This looks interesting, but now the tests needs to be fixed?

@GuillaumeSmaha
Copy link
Contributor Author

GuillaumeSmaha commented Jun 28, 2019

@jmini Yes sure :) I am going to fix it today
There are tests I didn't see by just calling mvnw clean install

@GuillaumeSmaha
Copy link
Contributor Author

GuillaumeSmaha commented Jun 28, 2019

This is finally not the good way to fix this issue.
The generation of openapi.yaml petstore in samples produces bad yaml file regarding the OpenApi v3 specification.
( I will add a diff)
I think it will need to remove the option MINIMIAE_QUOTES in io.swagger.v3.core.util.Yaml or wait for the fixes in fastxml/jackson :male_shrug:

@GuillaumeSmaha
Copy link
Contributor Author

Here the diff of one file:

diff --git a/samples/server/petstore/python-flask/openapi_server/openapi/openapi.yaml b/samples/server/petstore/python-flask/openapi_server/openapi/openapi.yaml
index 122782a9b9..243a96ff48 100644
--- a/samples/server/petstore/python-flask/openapi_server/openapi/openapi.yaml
+++ b/samples/server/petstore/python-flask/openapi_server/openapi/openapi.yaml
@@ -1,785 +1,950 @@
-openapi: 3.0.1
+---
+openapi: "3.0.1"
 info:
-  description: This is a sample server Petstore server. For this sample, you can use
-    the api key `special-key` to test the authorization filters.
+  description: "This is a sample server Petstore server. For this sample, you can\
+    \ use the api key `special-key` to test the authorization filters."
+  extensions: {}
   license:
-    name: Apache-2.0
-    url: http://www.apache.org/licenses/LICENSE-2.0.html
-  title: OpenAPI Petstore
-  version: 1.0.0
+    extensions: {}
+    name: "Apache-2.0"
+    url: "http://www.apache.org/licenses/LICENSE-2.0.html"
+  title: "OpenAPI Petstore"
+  version: "1.0.0"
 servers:
-- url: http://petstore.swagger.io/v2
+- url: "http://petstore.swagger.io/v2"
 tags:
-- description: Everything about your Pets
-  name: pet
-- description: Access to Petstore orders
-  name: store
-- description: Operations about user
-  name: user
+- description: "Everything about your Pets"
+  extensions: {}
+  name: "pet"
+- description: "Access to Petstore orders"
+  extensions: {}
+  name: "store"
+- description: "Operations about user"
+  extensions: {}
+  name: "user"
 paths:
   /pet:
+    extensions: {}
     post:
-      operationId: add_pet
+      extensions:
+        x-codegen-request-body-name: "body"
+        x-openapi-router-controller: "openapi_server.controllers.pet_controller"
+      operationId: "add_pet"
       requestBody:
         content:
           application/json:
             schema:
-              $ref: '#/components/schemas/Pet'
+              $ref: "#/components/schemas/Pet"
           application/xml:
             schema:
-              $ref: '#/components/schemas/Pet'
-        description: Pet object that needs to be added to the store
+              $ref: "#/components/schemas/Pet"
+        description: "Pet object that needs to be added to the store"
         required: true
       responses:
         405:
           content: {}
-          description: Invalid input
+          description: "Invalid input"
+          extensions: {}
       security:
       - petstore_auth:
-        - write:pets
-        - read:pets
-      summary: Add a new pet to the store
+        - "write:pets"
+        - "read:pets"
+      summary: "Add a new pet to the store"
       tags:
-      - pet
-      x-codegen-request-body-name: body
-      x-openapi-router-controller: openapi_server.controllers.pet_controller
+      - "pet"
     put:
-      operationId: update_pet
+      extensions:
+        x-codegen-request-body-name: "body"
+        x-openapi-router-controller: "openapi_server.controllers.pet_controller"
+      operationId: "update_pet"
       requestBody:
         content:
           application/json:
             schema:
-              $ref: '#/components/schemas/Pet'
+              $ref: "#/components/schemas/Pet"
           application/xml:
             schema:
-              $ref: '#/components/schemas/Pet'
-        description: Pet object that needs to be added to the store
+              $ref: "#/components/schemas/Pet"
+        description: "Pet object that needs to be added to the store"
         required: true
       responses:
         400:
           content: {}
-          description: Invalid ID supplied
+          description: "Invalid ID supplied"
+          extensions: {}
         404:
           content: {}
-          description: Pet not found
+          description: "Pet not found"
+          extensions: {}
         405:
           content: {}
-          description: Validation exception
+          description: "Validation exception"
+          extensions: {}
       security:
       - petstore_auth:
-        - write:pets
-        - read:pets
-      summary: Update an existing pet
+        - "write:pets"
+        - "read:pets"
+      summary: "Update an existing pet"
       tags:
-      - pet
-      x-codegen-request-body-name: body
-      x-openapi-router-controller: openapi_server.controllers.pet_controller
+      - "pet"
   /pet/findByStatus:
+    extensions: {}
     get:
-      description: Multiple status values can be provided with comma separated strings
-      operationId: find_pets_by_status
+      description: "Multiple status values can be provided with comma separated strings"
+      extensions:
+        x-openapi-router-controller: "openapi_server.controllers.pet_controller"
+      operationId: "find_pets_by_status"
       parameters:
-      - description: Status values that need to be considered for filter
+      - description: "Status values that need to be considered for filter"
         explode: false
-        in: query
-        name: status
+        extensions: {}
+        in: "query"
+        name: "status"
         required: true
         schema:
+          extensions: {}
           items:
-            default: available
+            default: "available"
             enum:
-            - available
-            - pending
-            - sold
-            type: string
-          type: array
-        style: form
+            - "available"
+            - "pending"
+            - "sold"
+            extensions: {}
+            type: "string"
+          type: "array"
+        style: "FORM"
       responses:
         200:
           content:
             application/xml:
               schema:
+                extensions: {}
                 items:
-                  $ref: '#/components/schemas/Pet'
-                type: array
+                  $ref: "#/components/schemas/Pet"
+                  extensions: {}
+                type: "array"
             application/json:
               schema:
+                extensions: {}
                 items:
-                  $ref: '#/components/schemas/Pet'
-                type: array
-          description: successful operation
+                  $ref: "#/components/schemas/Pet"
+                  extensions: {}
+                type: "array"
+          description: "successful operation"
+          extensions: {}
         400:
           content: {}
-          description: Invalid status value
+          description: "Invalid status value"
+          extensions: {}
       security:
       - petstore_auth:
-        - write:pets
-        - read:pets
-      summary: Finds Pets by status
+        - "write:pets"
+        - "read:pets"
+      summary: "Finds Pets by status"
       tags:
-      - pet
-      x-openapi-router-controller: openapi_server.controllers.pet_controller
+      - "pet"
   /pet/findByTags:
+    extensions: {}
     get:
       deprecated: true
-      description: Multiple tags can be provided with comma separated strings. Use
-        tag1, tag2, tag3 for testing.
-      operationId: find_pets_by_tags
+      description: "Multiple tags can be provided with comma separated strings. Use\
+        \ tag1, tag2, tag3 for testing."
+      extensions:
+        x-openapi-router-controller: "openapi_server.controllers.pet_controller"
+      operationId: "find_pets_by_tags"
       parameters:
-      - description: Tags to filter by
+      - description: "Tags to filter by"
         explode: false
-        in: query
-        name: tags
+        extensions: {}
+        in: "query"
+        name: "tags"
         required: true
         schema:
+          extensions: {}
           items:
-            type: string
-          type: array
-        style: form
+            extensions: {}
+            type: "string"
+          type: "array"
+        style: "FORM"
       responses:
         200:
           content:
             application/xml:
               schema:
+                extensions: {}
                 items:
-                  $ref: '#/components/schemas/Pet'
-                type: array
+                  $ref: "#/components/schemas/Pet"
+                  extensions: {}
+                type: "array"
             application/json:
               schema:
+                extensions: {}
                 items:
-                  $ref: '#/components/schemas/Pet'
-                type: array
-          description: successful operation
+                  $ref: "#/components/schemas/Pet"
+                  extensions: {}
+                type: "array"
+          description: "successful operation"
+          extensions: {}
         400:
           content: {}
-          description: Invalid tag value
+          description: "Invalid tag value"
+          extensions: {}
       security:
       - petstore_auth:
-        - write:pets
-        - read:pets
-      summary: Finds Pets by tags
+        - "write:pets"
+        - "read:pets"
+      summary: "Finds Pets by tags"
       tags:
-      - pet
-      x-openapi-router-controller: openapi_server.controllers.pet_controller
+      - "pet"
   /pet/{petId}:
     delete:
-      operationId: delete_pet
+      extensions:
+        x-openapi-router-controller: "openapi_server.controllers.pet_controller"
+      operationId: "delete_pet"
       parameters:
-      - in: header
-        name: api_key
+      - extensions: {}
+        in: "header"
+        name: "api_key"
         schema:
-          type: string
-      - description: Pet id to delete
-        in: path
-        name: petId
+          extensions: {}
+          type: "string"
+      - description: "Pet id to delete"
+        extensions: {}
+        in: "path"
+        name: "petId"
         required: true
         schema:
-          format: int64
-          type: integer
+          extensions: {}
+          format: "int64"
+          type: "integer"
       responses:
         400:
           content: {}
-          description: Invalid pet value
+          description: "Invalid pet value"
+          extensions: {}
       security:
       - petstore_auth:
-        - write:pets
-        - read:pets
-      summary: Deletes a pet
+        - "write:pets"
+        - "read:pets"
+      summary: "Deletes a pet"
       tags:
-      - pet
-      x-openapi-router-controller: openapi_server.controllers.pet_controller
+      - "pet"
+    extensions: {}
     get:
-      description: Returns a single pet
-      operationId: get_pet_by_id
+      description: "Returns a single pet"
+      extensions:
+        x-openapi-router-controller: "openapi_server.controllers.pet_controller"
+      operationId: "get_pet_by_id"
       parameters:
-      - description: ID of pet to return
-        in: path
-        name: petId
+      - description: "ID of pet to return"
+        extensions: {}
+        in: "path"
+        name: "petId"
         required: true
         schema:
-          format: int64
-          type: integer
+          extensions: {}
+          format: "int64"
+          type: "integer"
       responses:
         200:
           content:
             application/xml:
               schema:
-                $ref: '#/components/schemas/Pet'
+                $ref: "#/components/schemas/Pet"
+                extensions: {}
             application/json:
               schema:
-                $ref: '#/components/schemas/Pet'
-          description: successful operation
+                $ref: "#/components/schemas/Pet"
+                extensions: {}
+          description: "successful operation"
+          extensions: {}
         400:
           content: {}
-          description: Invalid ID supplied
+          description: "Invalid ID supplied"
+          extensions: {}
         404:
           content: {}
-          description: Pet not found
+          description: "Pet not found"
+          extensions: {}
       security:
       - api_key: []
-      summary: Find pet by ID
+      summary: "Find pet by ID"
       tags:
-      - pet
-      x-openapi-router-controller: openapi_server.controllers.pet_controller
+      - "pet"
     post:
-      operationId: update_pet_with_form
+      extensions:
+        x-openapi-router-controller: "openapi_server.controllers.pet_controller"
+      operationId: "update_pet_with_form"
       parameters:
-      - description: ID of pet that needs to be updated
-        in: path
-        name: petId
+      - description: "ID of pet that needs to be updated"
+        extensions: {}
+        in: "path"
+        name: "petId"
         required: true
         schema:
-          format: int64
-          type: integer
+          extensions: {}
+          format: "int64"
+          type: "integer"
       requestBody:
         content:
           application/x-www-form-urlencoded:
             schema:
               properties:
                 name:
-                  description: Updated name of the pet
-                  type: string
+                  description: "Updated name of the pet"
+                  extensions: {}
+                  type: "string"
                 status:
-                  description: Updated status of the pet
-                  type: string
+                  description: "Updated status of the pet"
+                  extensions: {}
+                  type: "string"
       responses:
         405:
           content: {}
-          description: Invalid input
+          description: "Invalid input"
+          extensions: {}
       security:
       - petstore_auth:
-        - write:pets
-        - read:pets
-      summary: Updates a pet in the store with form data
+        - "write:pets"
+        - "read:pets"
+      summary: "Updates a pet in the store with form data"
       tags:
-      - pet
-      x-openapi-router-controller: openapi_server.controllers.pet_controller
+      - "pet"
   /pet/{petId}/uploadImage:
+    extensions: {}
     post:
-      operationId: upload_file
+      extensions:
+        x-openapi-router-controller: "openapi_server.controllers.pet_controller"
+      operationId: "upload_file"
       parameters:
-      - description: ID of pet to update
-        in: path
-        name: petId
+      - description: "ID of pet to update"
+        extensions: {}
+        in: "path"
+        name: "petId"
         required: true
         schema:
-          format: int64
-          type: integer
+          extensions: {}
+          format: "int64"
+          type: "integer"
       requestBody:
         content:
           multipart/form-data:
             schema:
               properties:
                 additionalMetadata:
-                  description: Additional data to pass to server
-                  type: string
+                  description: "Additional data to pass to server"
+                  extensions: {}
+                  type: "string"
                 file:
-                  description: file to upload
-                  format: binary
-                  type: string
+                  description: "file to upload"
+                  extensions: {}
+                  format: "binary"
+                  type: "string"
       responses:
         200:
           content:
             application/json:
               schema:
-                $ref: '#/components/schemas/ApiResponse'
-          description: successful operation
+                $ref: "#/components/schemas/ApiResponse"
+                extensions: {}
+          description: "successful operation"
+          extensions: {}
       security:
       - petstore_auth:
-        - write:pets
-        - read:pets
-      summary: uploads an image
+        - "write:pets"
+        - "read:pets"
+      summary: "uploads an image"
       tags:
-      - pet
-      x-openapi-router-controller: openapi_server.controllers.pet_controller
+      - "pet"
   /store/inventory:
+    extensions: {}
     get:
-      description: Returns a map of status codes to quantities
-      operationId: get_inventory
+      description: "Returns a map of status codes to quantities"
+      extensions:
+        x-openapi-router-controller: "openapi_server.controllers.store_controller"
+      operationId: "get_inventory"
       responses:
         200:
           content:
             application/json:
               schema:
                 additionalProperties:
-                  format: int32
-                  type: integer
-                type: object
-          description: successful operation
+                  extensions: {}
+                  format: "int32"
+                  type: "integer"
+                extensions: {}
+                type: "object"
+          description: "successful operation"
+          extensions: {}
       security:
       - api_key: []
-      summary: Returns pet inventories by status
+      summary: "Returns pet inventories by status"
       tags:
-      - store
-      x-openapi-router-controller: openapi_server.controllers.store_controller
+      - "store"
   /store/order:
+    extensions: {}
     post:
-      operationId: place_order
+      extensions:
+        x-codegen-request-body-name: "body"
+        x-openapi-router-controller: "openapi_server.controllers.store_controller"
+      operationId: "place_order"
       requestBody:
         content:
           '*/*':
             schema:
-              $ref: '#/components/schemas/Order'
-        description: order placed for purchasing the pet
+              $ref: "#/components/schemas/Order"
+        description: "order placed for purchasing the pet"
         required: true
       responses:
         200:
           content:
             application/xml:
               schema:
-                $ref: '#/components/schemas/Order'
+                $ref: "#/components/schemas/Order"
+                extensions: {}
             application/json:
               schema:
-                $ref: '#/components/schemas/Order'
-          description: successful operation
+                $ref: "#/components/schemas/Order"
+                extensions: {}
+          description: "successful operation"
+          extensions: {}
         400:
           content: {}
-          description: Invalid Order
-      summary: Place an order for a pet
+          description: "Invalid Order"
+          extensions: {}
+      summary: "Place an order for a pet"
       tags:
-      - store
-      x-codegen-request-body-name: body
-      x-openapi-router-controller: openapi_server.controllers.store_controller
+      - "store"
   /store/order/{orderId}:
     delete:
-      description: For valid response try integer IDs with value < 1000. Anything
-        above 1000 or nonintegers will generate API errors
-      operationId: delete_order
+      description: "For valid response try integer IDs with value < 1000. Anything\
+        \ above 1000 or nonintegers will generate API errors"
+      extensions:
+        x-openapi-router-controller: "openapi_server.controllers.store_controller"
+      operationId: "delete_order"
       parameters:
-      - description: ID of the order that needs to be deleted
-        in: path
-        name: orderId
+      - description: "ID of the order that needs to be deleted"
+        extensions: {}
+        in: "path"
+        name: "orderId"
         required: true
         schema:
-          type: string
+          extensions: {}
+          type: "string"
       responses:
         400:
           content: {}
-          description: Invalid ID supplied
+          description: "Invalid ID supplied"
+          extensions: {}
         404:
           content: {}
-          description: Order not found
-      summary: Delete purchase order by ID
+          description: "Order not found"
+          extensions: {}
+      summary: "Delete purchase order by ID"
       tags:
-      - store
-      x-openapi-router-controller: openapi_server.controllers.store_controller
+      - "store"
+    extensions: {}
     get:
-      description: For valid response try integer IDs with value <= 5 or > 10. Other
-        values will generated exceptions
-      operationId: get_order_by_id
+      description: "For valid response try integer IDs with value <= 5 or > 10. Other\
+        \ values will generated exceptions"
+      extensions:
+        x-openapi-router-controller: "openapi_server.controllers.store_controller"
+      operationId: "get_order_by_id"
       parameters:
-      - description: ID of pet that needs to be fetched
-        in: path
-        name: orderId
+      - description: "ID of pet that needs to be fetched"
+        extensions: {}
+        in: "path"
+        name: "orderId"
         required: true
         schema:
-          format: int64
+          extensions: {}
+          format: "int64"
           maximum: 5
           minimum: 1
-          type: integer
+          type: "integer"
       responses:
         200:
           content:
             application/xml:
               schema:
-                $ref: '#/components/schemas/Order'
+                $ref: "#/components/schemas/Order"
+                extensions: {}
             application/json:
               schema:
-                $ref: '#/components/schemas/Order'
-          description: successful operation
+                $ref: "#/components/schemas/Order"
+                extensions: {}
+          description: "successful operation"
+          extensions: {}
         400:
           content: {}
-          description: Invalid ID supplied
+          description: "Invalid ID supplied"
+          extensions: {}
         404:
           content: {}
-          description: Order not found
-      summary: Find purchase order by ID
+          description: "Order not found"
+          extensions: {}
+      summary: "Find purchase order by ID"
       tags:
-      - store
-      x-openapi-router-controller: openapi_server.controllers.store_controller
+      - "store"
   /user:
+    extensions: {}
     post:
-      description: This can only be done by the logged in user.
-      operationId: create_user
+      description: "This can only be done by the logged in user."
+      extensions:
+        x-codegen-request-body-name: "body"
+        x-openapi-router-controller: "openapi_server.controllers.user_controller"
+      operationId: "create_user"
       requestBody:
         content:
           '*/*':
             schema:
-              $ref: '#/components/schemas/User'
-        description: Created user object
+              $ref: "#/components/schemas/User"
+        description: "Created user object"
         required: true
       responses:
         default:
           content: {}
-          description: successful operation
-      summary: Create user
+          description: "successful operation"
+          extensions: {}
+      summary: "Create user"
       tags:
-      - user
-      x-codegen-request-body-name: body
-      x-openapi-router-controller: openapi_server.controllers.user_controller
+      - "user"
   /user/createWithArray:
+    extensions: {}
     post:
-      operationId: create_users_with_array_input
+      extensions:
+        x-codegen-request-body-name: "body"
+        x-openapi-router-controller: "openapi_server.controllers.user_controller"
+      operationId: "create_users_with_array_input"
       requestBody:
         content:
           '*/*':
             schema:
               items:
-                $ref: '#/components/schemas/User'
-              type: array
-        description: List of user object
+                $ref: "#/components/schemas/User"
+                extensions: {}
+              type: "array"
+        description: "List of user object"
         required: true
       responses:
         default:
           content: {}
-          description: successful operation
-      summary: Creates list of users with given input array
+          description: "successful operation"
+          extensions: {}
+      summary: "Creates list of users with given input array"
       tags:
-      - user
-      x-codegen-request-body-name: body
-      x-openapi-router-controller: openapi_server.controllers.user_controller
+      - "user"
   /user/createWithList:
+    extensions: {}
     post:
-      operationId: create_users_with_list_input
+      extensions:
+        x-codegen-request-body-name: "body"
+        x-openapi-router-controller: "openapi_server.controllers.user_controller"
+      operationId: "create_users_with_list_input"
       requestBody:
         content:
           '*/*':
             schema:
               items:
-                $ref: '#/components/schemas/User'
-              type: array
-        description: List of user object
+                $ref: "#/components/schemas/User"
+                extensions: {}
+              type: "array"
+        description: "List of user object"
         required: true
       responses:
         default:
           content: {}
-          description: successful operation
-      summary: Creates list of users with given input array
+          description: "successful operation"
+          extensions: {}
+      summary: "Creates list of users with given input array"
       tags:
-      - user
-      x-codegen-request-body-name: body
-      x-openapi-router-controller: openapi_server.controllers.user_controller
+      - "user"
   /user/login:
+    extensions: {}
     get:
-      operationId: login_user
+      extensions:
+        x-openapi-router-controller: "openapi_server.controllers.user_controller"
+      operationId: "login_user"
       parameters:
-      - description: The user name for login
-        in: query
-        name: username
+      - description: "The user name for login"
+        extensions: {}
+        in: "query"
+        name: "username"
         required: true
         schema:
-          type: string
-      - description: The password for login in clear text
-        in: query
-        name: password
+          extensions: {}
+          type: "string"
+      - description: "The password for login in clear text"
+        extensions: {}
+        in: "query"
+        name: "password"
         required: true
         schema:
-          type: string
+          extensions: {}
+          type: "string"
       responses:
         200:
           content:
             application/xml:
               schema:
-                type: string
+                extensions: {}
+                type: "string"
             application/json:
               schema:
-                type: string
-          description: successful operation
+                extensions: {}
+                type: "string"
+          description: "successful operation"
+          extensions: {}
           headers:
             X-Rate-Limit:
-              description: calls per hour allowed by the user
+              description: "calls per hour allowed by the user"
               schema:
-                format: int32
-                type: integer
+                extensions: {}
+                format: "int32"
+                type: "integer"
             X-Expires-After:
-              description: date in UTC when toekn expires
+              description: "date in UTC when toekn expires"
               schema:
-                format: date-time
-                type: string
+                extensions: {}
+                format: "date-time"
+                type: "string"
         400:
           content: {}
-          description: Invalid username/password supplied
-      summary: Logs user into the system
+          description: "Invalid username/password supplied"
+          extensions: {}
+      summary: "Logs user into the system"
       tags:
-      - user
-      x-openapi-router-controller: openapi_server.controllers.user_controller
+      - "user"
   /user/logout:
+    extensions: {}
     get:
-      operationId: logout_user
+      extensions:
+        x-openapi-router-controller: "openapi_server.controllers.user_controller"
+      operationId: "logout_user"
       responses:
         default:
           content: {}
-          description: successful operation
-      summary: Logs out current logged in user session
+          description: "successful operation"
+          extensions: {}
+      summary: "Logs out current logged in user session"
       tags:
-      - user
-      x-openapi-router-controller: openapi_server.controllers.user_controller
+      - "user"
   /user/{username}:
     delete:
-      description: This can only be done by the logged in user.
-      operationId: delete_user
+      description: "This can only be done by the logged in user."
+      extensions:
+        x-openapi-router-controller: "openapi_server.controllers.user_controller"
+      operationId: "delete_user"
       parameters:
-      - description: The name that needs to be deleted
-        in: path
-        name: username
+      - description: "The name that needs to be deleted"
+        extensions: {}
+        in: "path"
+        name: "username"
         required: true
         schema:
-          type: string
+          extensions: {}
+          type: "string"
       responses:
         400:
           content: {}
-          description: Invalid username supplied
+          description: "Invalid username supplied"
+          extensions: {}
         404:
           content: {}
-          description: User not found
-      summary: Delete user
+          description: "User not found"
+          extensions: {}
+      summary: "Delete user"
       tags:
-      - user
-      x-openapi-router-controller: openapi_server.controllers.user_controller
+      - "user"
+    extensions: {}
     get:
-      operationId: get_user_by_name
+      extensions:
+        x-openapi-router-controller: "openapi_server.controllers.user_controller"
+      operationId: "get_user_by_name"
       parameters:
-      - description: The name that needs to be fetched. Use user1 for testing.
-        in: path
-        name: username
+      - description: "The name that needs to be fetched. Use user1 for testing."
+        extensions: {}
+        in: "path"
+        name: "username"
         required: true
         schema:
-          type: string
+          extensions: {}
+          type: "string"
       responses:
         200:
           content:
             application/xml:
               schema:
-                $ref: '#/components/schemas/User'
+                $ref: "#/components/schemas/User"
+                extensions: {}
             application/json:
               schema:
-                $ref: '#/components/schemas/User'
-          description: successful operation
+                $ref: "#/components/schemas/User"
+                extensions: {}
+          description: "successful operation"
+          extensions: {}
         400:
           content: {}
-          description: Invalid username supplied
+          description: "Invalid username supplied"
+          extensions: {}
         404:
           content: {}
-          description: User not found
-      summary: Get user by user name
+          description: "User not found"
+          extensions: {}
+      summary: "Get user by user name"
       tags:
-      - user
-      x-openapi-router-controller: openapi_server.controllers.user_controller
+      - "user"
     put:
-      description: This can only be done by the logged in user.
-      operationId: update_user
+      description: "This can only be done by the logged in user."
+      extensions:
+        x-codegen-request-body-name: "body"
+        x-openapi-router-controller: "openapi_server.controllers.user_controller"
+      operationId: "update_user"
       parameters:
-      - description: name that need to be deleted
-        in: path
-        name: username
+      - description: "name that need to be deleted"
+        extensions: {}
+        in: "path"
+        name: "username"
         required: true
         schema:
-          type: string
+          extensions: {}
+          type: "string"
       requestBody:
         content:
           '*/*':
             schema:
-              $ref: '#/components/schemas/User'
-        description: Updated user object
+              $ref: "#/components/schemas/User"
+        description: "Updated user object"
         required: true
       responses:
         400:
           content: {}
-          description: Invalid user supplied
+          description: "Invalid user supplied"
+          extensions: {}
         404:
           content: {}
-          description: User not found
-      summary: Updated user
+          description: "User not found"
+          extensions: {}
+      summary: "Updated user"
       tags:
-      - user
-      x-codegen-request-body-name: body
-      x-openapi-router-controller: openapi_server.controllers.user_controller
+      - "user"
 components:
   schemas:
     Order:
-      description: An order for a pets from the pet store
+      description: "An order for a pets from the pet store"
       example:
         petId: 6
         quantity: 1
         id: 0
-        shipDate: 2000-01-23T04:56:07.000+00:00
+        shipDate: "2000-01-23T04:56:07.000+00:00"
         complete: false
-        status: placed
+        status: "placed"
       properties:
         id:
-          format: int64
-          type: integer
+          extensions: {}
+          format: "int64"
+          type: "integer"
         petId:
-          format: int64
-          type: integer
+          extensions: {}
+          format: "int64"
+          type: "integer"
         quantity:
-          format: int32
-          type: integer
+          extensions: {}
+          format: "int32"
+          type: "integer"
         shipDate:
-          format: date-time
-          type: string
+          extensions: {}
+          format: "date-time"
+          type: "string"
         status:
-          description: Order Status
+          description: "Order Status"
           enum:
-          - placed
-          - approved
-          - delivered
-          type: string
+          - "placed"
+          - "approved"
+          - "delivered"
+          extensions: {}
+          type: "string"
         complete:
           default: false
-          type: boolean
-      title: Pet Order
-      type: object
+          extensions: {}
+          type: "boolean"
+      title: "Pet Order"
+      type: "object"
       xml:
-        name: Order
+        name: "Order"
     Category:
-      description: A category for a pet
+      description: "A category for a pet"
       example:
-        name: name
+        name: "name"
         id: 6
       properties:
         id:
-          format: int64
-          type: integer
+          extensions: {}
+          format: "int64"
+          type: "integer"
         name:
-          type: string
-      title: Pet category
-      type: object
+          extensions: {}
+          type: "string"
+      title: "Pet category"
+      type: "object"
       xml:
-        name: Category
+        name: "Category"
     User:
-      description: A User who is purchasing from the pet store
+      description: "A User who is purchasing from the pet store"
       example:
-        firstName: firstName
-        lastName: lastName
-        password: password
+        firstName: "firstName"
+        lastName: "lastName"
+        password: "password"
         userStatus: 6
-        phone: phone
+        phone: "phone"
         id: 0
-        email: email
-        username: username
+        email: "email"
+        username: "username"
       properties:
         id:
-          format: int64
-          type: integer
+          extensions: {}
+          format: "int64"
+          type: "integer"
         username:
-          type: string
+          extensions: {}
+          type: "string"
         firstName:
-          type: string
+          extensions: {}
+          type: "string"
         lastName:
-          type: string
+          extensions: {}
+          type: "string"
         email:
-          type: string
+          extensions: {}
+          type: "string"
         password:
-          type: string
+          extensions: {}
+          type: "string"
         phone:
-          type: string
+          extensions: {}
+          type: "string"
         userStatus:
-          description: User Status
-          format: int32
-          type: integer
-      title: a User
-      type: object
+          description: "User Status"
+          extensions: {}
+          format: "int32"
+          type: "integer"
+      title: "a User"
+      type: "object"
       xml:
-        name: User
+        name: "User"
     Tag:
-      description: A tag for a pet
+      description: "A tag for a pet"
       example:
-        name: name
+        name: "name"
         id: 1
       properties:
         id:
-          format: int64
-          type: integer
+          extensions: {}
+          format: "int64"
+          type: "integer"
         name:
-          type: string
-      title: Pet Tag
-      type: object
+          extensions: {}
+          type: "string"
+      title: "Pet Tag"
+      type: "object"
       xml:
-        name: Tag
+        name: "Tag"
     Pet:
-      description: A pet for sale in the pet store
+      description: "A pet for sale in the pet store"
       example:
         photoUrls:
-        - photoUrls
-        - photoUrls
-        name: doggie
+        - "photoUrls"
+        - "photoUrls"
+        name: "doggie"
         id: 0
         category:
-          name: name
+          name: "name"
           id: 6
         tags:
-        - name: name
+        - name: "name"
           id: 1
-        - name: name
+        - name: "name"
           id: 1
-        status: available
+        status: "available"
       properties:
         id:
-          format: int64
-          type: integer
+          extensions: {}
+          format: "int64"
+          type: "integer"
         category:
-          $ref: '#/components/schemas/Category'
+          $ref: "#/components/schemas/Category"
+          extensions: {}
         name:
-          example: doggie
-          type: string
+          example: "doggie"
+          extensions: {}
+          type: "string"
         photoUrls:
+          extensions: {}
           items:
-            type: string
-          type: array
+            extensions: {}
+            type: "string"
+          type: "array"
           xml:
-            name: photoUrl
+            name: "photoUrl"
             wrapped: true
         tags:
+          extensions: {}
           items:
-            $ref: '#/components/schemas/Tag'
-          type: array
+            $ref: "#/components/schemas/Tag"
+            extensions: {}
+          type: "array"
           xml:
-            name: tag
+            name: "tag"
             wrapped: true
         status:
-          description: pet status in the store
+          description: "pet status in the store"
           enum:
-          - available
-          - pending
-          - sold
-          type: string
+          - "available"
+          - "pending"
+          - "sold"
+          extensions: {}
+          type: "string"
       required:
-      - name
-      - photoUrls
-      title: a Pet
-      type: object
+      - "name"
+      - "photoUrls"
+      title: "a Pet"
+      type: "object"
       xml:
-        name: Pet
+        name: "Pet"
     ApiResponse:
-      description: Describes the result of uploading an image resource
+      description: "Describes the result of uploading an image resource"
       example:
         code: 0
-        type: type
-        message: message
+        type: "type"
+        message: "message"
       properties:
         code:
-          format: int32
-          type: integer
+          extensions: {}
+          format: "int32"
+          type: "integer"
         type:
-          type: string
+          extensions: {}
+          type: "string"
         message:
-          type: string
-      title: An uploaded response
-      type: object
+          extensions: {}
+          type: "string"
+      title: "An uploaded response"
+      type: "object"
   securitySchemes:
     petstore_auth:
+      extensions:
+        x-tokenInfoFunc: "openapi_server.controllers.security_controller_.info_from_petstore_auth"
+        x-scopeValidateFunc: "openapi_server.controllers.security_controller_.validate_scope_petstore_auth"
       flows:
         implicit:
-          authorizationUrl: http://petstore.swagger.io/api/oauth/dialog
+          authorizationUrl: "http://petstore.swagger.io/api/oauth/dialog"
           scopes:
-            write:pets: modify pets in your account
-            read:pets: read your pets
-      type: oauth2
-      x-tokenInfoFunc: openapi_server.controllers.security_controller_.info_from_petstore_auth
-      x-scopeValidateFunc: openapi_server.controllers.security_controller_.validate_scope_petstore_auth
+            write:pets: "modify pets in your account"
+            read:pets: "read your pets"
+      type: "OAUTH2"
     api_key:
-      in: header
-      name: api_key
-      type: apiKey
-      x-apikeyInfoFunc: openapi_server.controllers.security_controller_.info_from_api_key
+      extensions:
+        x-apikeyInfoFunc: "openapi_server.controllers.security_controller_.info_from_api_key"
+      in: "HEADER"
+      name: "api_key"
+      type: "APIKEY"

@jimschubert
Copy link
Member

@GuillaumeSmaha sorry this got buried, I'm not sure where Jeremie left off in your discussion but wanted to comment. We appreciate the effort put into this.

I've just opened #5933 to fix this issue by exposing a system property to users (-Dorg.openapitools.codegen.utils.yaml.minimize.quotes=false). This would result in all string contents being quoted in the output.

The implementation in this PR isn't viable because of the differences between the YAML implementations. Our object model is OpenAPI 3.x, regardless of the version of the input spec. This PR would result in changes to how enums and maps are serialized, while dropping all extensions for OpenAPI 3.x.

The v3 YAML factory configures the following features:

factory.disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER);
factory.enable(YAMLGenerator.Feature.MINIMIZE_QUOTES);
factory.enable(YAMLGenerator.Feature.SPLIT_LINES);
factory.enable(YAMLGenerator.Feature.ALWAYS_QUOTE_NUMBERS_AS_STRINGS);
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

It also provides a custom serializer for objects containing only $ref and adds a "mixin" (ExtensionsMixin, catches all unknown properties) to a ton of v3 types:

  • ApiResponses
  • ApiResponse
  • Callback
  • Components
  • Contact
  • Encoding
  • EncodingProperty
  • Example
  • ExternalDocumentation
  • Header
  • Info
  • License
  • Link
  • LinkParameter
  • MediaType
  • OAuthFlow
  • OAuthFlows
  • OpenAPI
  • Operation
  • Parameter
  • PathItem
  • Paths
  • RequestBody
  • Scopes
  • SecurityScheme
  • Server
  • ServerVariable
  • ServerVariables
  • Tag
  • XML
  • Schema
  • DateSchema

The YAML serializer in this PR offers much less functionality. This is the entirety of it's feature set (compare the configure statements with those from the v3 version above):

ObjectMapper mapper = jsonFactory == null ? new ObjectMapper() : new ObjectMapper(jsonFactory);
Module deserializerModule = new DeserializationModule(includePathDeserializer, includeResponseDeserializer);
mapper.registerModule(deserializerModule);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.addMixIn(Response.class, ResponseSchemaMixin.class);
ReferenceSerializationConfigurer.serializeAsComputedRef(mapper);

In addition to the above, there are a handful of custom deserializers which wouldn't affect the to-string in this PR.

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