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

Properties on the same level as anyOf/oneOf/... are missing and anyOf merge is illogical #810

Closed
m-mohr opened this issue Feb 7, 2019 · 20 comments

Comments

@m-mohr
Copy link
Contributor

m-mohr commented Feb 7, 2019

If I specify a schema for an object, which has properties and in addition some optional schemas it could conform to, the properties are not shown.

Example:

openapi: 3.0.2
info:
  title: Example
  version: 0.4.0
paths:
  '/example':
    get:
      responses:
        '200':
          description: 'cube:properties is not shown in the schema'
          content:
            application/json:
              schema:
                type: object
                required:
                  - 'cube:dimensions'
                properties:
                  'cube:dimensions':
                    type: object
                    oneOf:
                      - title: Spatial Dimension
                        type: object
                      - title: Temporal Dimension
                        type: object
                anyOf:
                  - $ref: '#/components/schemas/collection_eo'
                  - $ref: '#/components/schemas/collection_sar'
                  - $ref: '#/components/schemas/collection_sci'
components:
  schemas:
    collection_eo:
      type: object
      format: eo
    collection_sar:
      type: object
      format: sar
    collection_sci:
      type: object
      format: sci

I would cube:dimensions expect to show up in ReDoc as it does in Swagger Editor:
image

Tested with ReDoc standalone version 2.0.0-rc.2

@m-mohr m-mohr changed the title property and anyOf/oneOf/... on one level => property not shown properties and anyOf/oneOf/... on one level => property not shown Feb 7, 2019
@m-mohr m-mohr changed the title properties and anyOf/oneOf/... on one level => property not shown properties and anyOf/oneOf/... on one level => properties not shown Feb 7, 2019
@m-mohr
Copy link
Contributor Author

m-mohr commented Feb 11, 2019

@RomanGotsiy I just tried to find out at which point it stopped working and it seems it was between alpha 37 and alpha 38, so commit 39b930d looks suspicious. Especially the change to variant in line 164 of the Schema.ts. Seems the merging doesn't work any longer. (Can't confirm as yarn install fails on windows.)

@m-mohr
Copy link
Contributor Author

m-mohr commented Feb 12, 2019

In addition, merging the "base schema" with anyOf doesn't make sense. It works well for oneOf, but for anyOf it changes the logic. The base schema needs to be listed independently from anyOf schemas as Swagger Editor does (see screenshot above).

Example: A required property in a base schema is always required independently whether zero, one or multiple schemas from anyOf are used. But if you merge the required property into anyOf, it actually is not required any longer as anyOf means you can also use zero of the schemas. So the required field would just be required if one or more schemas are used from anyOf, but it is valid to use none and in this case the required field from the base schema is missing.

@m-mohr m-mohr changed the title properties and anyOf/oneOf/... on one level => properties not shown Properties on the same level as anyOf/oneOf/... are missing and anyOf merge is illogical Feb 12, 2019
@m-mohr
Copy link
Contributor Author

m-mohr commented Mar 11, 2019

@RomanGotsiy Is there anything I can help with to get this solved? It's quite annoying that properties don't get rendered and so having people complain about because that they need to dig in the openAPI file as the ReDoc rendered version is not reliable.

@RomanHotsiy
Copy link
Member

@m-mohr oh. Sorry for the delay. This is just a complex issue which takes a lot of mental efforts to just understand it. So that's why I'm delaying it...

I will try to look into it tomorrow but can't promise anything.

@RomanHotsiy
Copy link
Member

as anyOf means you can also use zero of the schemas.

I don't know where did you learn it from but according to the JSON schema spec:

image

So, merging seems to be valid.

@m-mohr
Copy link
Contributor Author

m-mohr commented Mar 15, 2019

@RomanGotsiy Thank you very much! I highly appreciate the work you do here as it far exceeds the usual level of support open-source projects receive!

Indeed, I don't know why I thought it means zero or more. Sorry about the wrong information. So merging is valid for anyOf, allOf and oneOf and works well. Just tested it with rc3.

@RomanHotsiy
Copy link
Member

Thanks for the kind words!
Again sorry for ignoring some of your issues. They are usually complex to simply understand so I have to stew on each 🤯

@meteozond
Copy link

Just for clarification, is using #ref inside anyOf within property like this legal?

{
    "properties": {
        "property": {
            "title": "Property title",
            "desciption": "Property description",
            "anyOf": [
                "$ref": "#/components/schemas/SomeDefinition"
            ]
        }
    }
}

@m-mohr
Copy link
Contributor Author

m-mohr commented Sep 25, 2019

@meteozond No, you need to wrap the ref in an object. Arrays can't contain key-value-pairs.

@meteozond
Copy link

@m-mohr, it is was typo, ref is definitely have be wrapped by object. But is it valid due to $ref nature?

{
    "properties": {
        "property": {
            "title": "Property title",
            "desciption": "Property description",
            "anyOf": [
                {"$ref": "#/components/schemas/SomeDefinition"}
            ]
        }
    }

@m-mohr
Copy link
Contributor Author

m-mohr commented Oct 9, 2019

@meteozond Should be valid, but I would assume that tooling could get confused. What I personally prefer is using anyOf/allOf/oneOf without other siblings:

{
  "properties": {
    "property": {
      "anyOf": [
        {
          "title": "Property title",
          "desciption": "Property description"
        },
        {
          "$ref": "#/components/schemas/SomeDefinition"
        }
      ]
    }
  }
}

@meteozond
Copy link

@m-mohr The problem is that redoc (and swagger-ui too) will show it like two possible values for that property. Instead of expected using title and description for property and its' only one possible value schema. In my case it will be shown like this:
Screen Shot 2019-10-10 at 11 19 49

And your solution like this:

Screen Shot 2019-10-10 at 11 21 47

@m-mohr
Copy link
Contributor Author

m-mohr commented Oct 10, 2019

@meteozond Oh, sorry, my mistake. I meant allOf instead of anyOf:

{
  "properties": {
    "property": {
      "allOf": [
        {
          "$ref": "#/components/schemas/SomeDefinition"
        },
        {
          "title": "Property title",
          "desciption": "Property description"
        }
      ]
    }
  }
}

Not sure how that's shown in the UI though.

@meteozond
Copy link

meteozond commented Oct 10, 2019

@m-mohr In your case

  1. We wont see property title and description in UI.

Screen Shot 2019-10-10 at 12 33 21

@RomanHotsiy, could you clarify how can we pass property only title, description and other attributes, if this property accepts object wich schema is defined as $ref?

@m-mohr
Copy link
Contributor Author

m-mohr commented Oct 10, 2019

@meteozond That sounds like a bug or could be a matter of array order. Could you provide a full example that I could copy/paste into Swagger Editor etc?

@meteozond
Copy link

@m-mohr You are right - order is meter (first is more important). But

  1. Property title still isn't shown by redoc.

Screen Shot 2019-10-10 at 14 47 37

  1. It is not my goal actually. With your solution I'm saying that this property:

accepts some object wich schema is the result of merging two these schemas.

But I want to say that this property:

  • has got these title and description,
  • takes object of schema defined by $ref.

Here is my schema example with your solution applied:

{
  "openapi": "3.0.2",
  "info": {
    "title": "",
    "version": ""
  },
  "paths": {
    "/api/v1/dependant/{_uid}/": {
      "get": {
        "operationId": "retrieveDependant",
        "parameters": [
          {
            "name": "_uid",
            "in": "path",
            "required": true,
            "description": "",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Dependant"
                }
              }
            },
            "description": ""
          }
        }
      },
      "put": {
        "operationId": "updateDependant",
        "parameters": [
          {
            "name": "_uid",
            "in": "path",
            "required": true,
            "description": "",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Dependant"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Dependant"
                }
              }
            },
            "description": ""
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Dependant": {
        "properties": {
          "_uid": {
            "type": "string",
            "title": " uid",
            "readOnly": true
          },
          "name": {
            "type": "string",
            "title": "Dependant name"
          },
          "property": {
            "allOf": [
              {
                "title": "Dependence property title",
                "description": "Dependence property description"
              },
              {
                "$ref": "#/components/schemas/Dependence"
              }
            ]
          }
        },
        "required": ["name"],
        "title": "Dependant title",
        "description": "Dependant description"
      },
      "Dependence": {
        "properties": {
          "_uid": {
            "type": "string",
            "title": " uid",
            "readOnly": true
          },
          "name": {
            "type": "string",
            "title": "Dependence name"
          }
        },
        "required": ["name"],
        "title": "Dependence title",
        "description": "Dependence description"
      }
    }
  }
}

@m-mohr
Copy link
Contributor Author

m-mohr commented Oct 10, 2019

  1. Property title still isn't shown by redoc.

Looks like a bug or not yet implemented feature. In the previous examples the title was never shown, except as titles of the buttons when you used anyOf. But using anyOf doesn't make much sense with just one schema.

  1. It is not my goal actually. With your solution I'm saying that this property:

accepts some object wich schema is the result of merging two these schemas.

But I want to say that this property:

  • has got these title and description,
  • takes object of schema defined by $ref.

What's the difference? You are defining a title/description for a schema anyway (you are defining things in the schemas part). You don't want to define a schema of a schema, right?

@meteozond
Copy link

@m-mohr The difference is at the definition level.
I think that property attrs have to be defined on the property level.
You are defining it inside the value-object - on the value level. This doesn't make sense for me. Is this the same object (should be same) or something else (with other properties)?

@m-mohr
Copy link
Contributor Author

m-mohr commented Oct 10, 2019

I don't get that. Schemas are always about the values. There is not really a different level (e.g. property level).

@meteozond
Copy link

@m-mohr Looks like we've got third solution from @RomanHotsiy )

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

No branches or pull requests

3 participants