Skip to content

Discriminator: how properly detect valid reference #2520

Closed

Description

@Logioniz

Suppose we have such OpenAPI document which served by location http://example.com/openapi/desc

servers:
    - url: 'http://example.com/'
components:
    schemas:
        Pet:
          type: object
          required:
          - petType
          properties:
            petType:
              type: string
          discriminator:
            propertyName: petType
            mapping:
              dog: Dog
        Cat:
          allOf:
          - $ref: '#/components/schemas/Pet'
          - type: object
            # all other properties specific to a `Cat`
            properties:
              name:
                type: string
        Dog:
          allOf:
          - $ref: '#/components/schemas/Pet'
          - type: object
            # all other properties specific to a `Dog`
            properties:
              bark:
                type: string
        Lizard:
          allOf:
          - $ref: '#/components/schemas/Pet'
          - type: object
            # all other properties specific to a `Lizard`
            properties:
              lovesRocks:
                type: boolean

it is not clear what mean Dog in the mapping subscheme.
Variants:

  1. http://example.com/openapi/Dog (accroding to base uri http://example.com/openapi/desc)
  2. #/components/schemas/Dog

If i have subschema in another url (http://example.com/openapi/Dog) thеn Dog is relative link.
If i have subschema in components thеn Dog is #/components/schemas/Dog (which is also a relative link, but different)

How to correctly determine that Dog is a relative link or subschema in #/components/schema?

Sorry for bad english.

Activity

  1. Logioniz commented on Apr 12, 2021

    @Logioniz
    ContributorAuthor

    Any recommendations?
    Not sure how to properly handle this kind of situation.

  2. jdesrosiers commented on Apr 12, 2021

    @jdesrosiers
    Contributor

    (Note: I deleted my previous wrong response)

    I believe is example has a bug. The values of mapping are URIs that must match the URI of one of the schemas being discriminated. I don't think OpenAPI has a concept of an identifier the way JSON Schema does. In that case, Dog doesn't have anything to resolve against and that is an invalid reference. If OpenAPI does have a concept of an identifier, then it would resolve to http://example.com/openapi/Dog, which doesn't exist. Constructing #/components/schemas/Dog should only happen when auto mapping, not with mapping.

    The discriminator in the example should be,

    discriminator:
      propertyName: petType
      mapping:
        dog: '#/components/schemas/Dog'
  3. Logioniz commented on Apr 13, 2021

    @Logioniz
    ContributorAuthor

    I believe is example has a bug.

    This example is taken from the specification (see the example in the end of discriminator object), i.e. I have not invented it. I understand correctly that you want to say that this is a bug in the documentation description (or bug in example in documentation)?

    If the construction of the #/components/schemas/Dog will be done only with auto-mapping, then in my opinion this will solve the problem too. In such case mapping MUST have ONLY reference, so my example MUST resolve it via http://example.com/openapi/Dog (based on base uri http://example.com/openapi/desc).

    At the moment I'm trying to figure out, should I handle this situation like this, or is it under discussion?

  4. jdesrosiers commented on Apr 13, 2021

    @jdesrosiers
    Contributor

    I didn't think you made it up. I recognized it as the example is from the documentation. Yes, I believe the example from the documentation has a bug.

    I don't think that OpenAPI has a concept of a base URI, so I don't think you can resolve Dog against http://example.com/openapi/desc. I think Dog is just an invalid reference. It needs to be an absolute URI. I could be wrong about that part.

  5. Logioniz commented on Apr 14, 2021

    @Logioniz
    ContributorAuthor

    @jdesrosiers thanks for your reply.

    I don't think that OpenAPI has a concept of a base URI

    Hmm... Maybe i misunderstood the documentation. Pay attention to part of the specification Relative References in URLs. For me, this part is not very clear and requires clarification.
    From specification:

    Relative references are resolved using the URLs defined in the Server Object as a Base URI.

    I think what is meant here is about url in the subscheme paths (i do not know of any other examples of what this might mean, for me it is not clear).
    There is a special note for $ref:

    Relative references used in $ref are processed as per JSON Reference, using the URL of the current document as the base URI

    Thus, if OpenAPI is served by url http://example.com/openapi/desc, then it is the base url for $ref. It means that you may to split your OpenAPI description for several files like this:

    openapi: '3.0.3'
    servers:
        - url: 'http://example.com/'
    paths:
      /company:
        $ref: 'company.yml#/paths/~1company'
    

    Suppose that this OpenAPI description served by url http://example.com/openapi/main.yml, then

    'http://example.com/' is a base URI for /company, so absolute url is 'http://example.com/company'.
    'http://example.com/openapi/main.yml' is a base URI for 'company.yml#/paths/~1company', so absolute url is 'http://example.com/openapi/company.yml#/paths/~1company'

  6. jdesrosiers commented on Apr 14, 2021

    @jdesrosiers
    Contributor

    I agree with your conclusion. This is what I missed,

    Relative references are resolved using the URLs defined in the Server Object as a Base URI.

    That is very clear. So, I agree that in the previous example, Dog would resolve to http://example.com/openapi/Dog.

  7. karenetheridge commented on Oct 13, 2021

    @karenetheridge
    Member

    This appears to have been fixed in the spec now. https://spec.openapis.org/oas/v3.1.0#discriminator-object has the example:

    MyResponseType:
      oneOf:
      - $ref: '#/components/schemas/Cat'
      - $ref: '#/components/schemas/Dog'
      - $ref: '#/components/schemas/Lizard'
      - $ref: 'https://gigantic-server.com/schemas/Monster/schema.json'
      discriminator:
        propertyName: petType
        mapping:
          dog: '#/components/schemas/Dog'
          monster: 'https://gigantic-server.com/schemas/Monster/schema.json'
    

    where the dog mapping properly has the uri reference, rather than just a snippet "Dog".

  8. MaceWindu commented on May 27, 2022

    @MaceWindu

    No, it wasn't. Last example still use Dog

    BTW, I've come here, because I've stumbled upon real openapi document which use this notation https://github.com/LandRegistry/digital-street-conveyancer-api/blob/master/src/main/resources/openapi.json#L730-L731

    and expect it resolved to #/components/schemas/<name> ...

  9. jdesrosiers commented on May 27, 2022

    @jdesrosiers
    Contributor

    I was wrong that "schema names" are not allowed in mapping. The spec says mapping is "an object to hold mappings between payload values and schema names or references". (The spec never defines what "schema names" means, but it's assumed that it means the property names used under /components/schemas which is equivalent to #/components/schemas/{schema name}.) Since a schema name is also a valid URI, there definitely seems to be an ambiguity in the spec.

    I think the most reasonable thing to do would be to assume it's a schema name if it looks like a schema name and fallback to treating it like a URI if that schema doesn't exist. It would be nice if there was a linting rule to flag the use of schema names in mapping as something to be avoided.

  10. self-assigned this
    on May 19, 2024
  11. added this to the v3.0.4 milestone on May 22, 2024
  12. handrews commented on Jun 6, 2024

    @handrews
    Member

    PRs merged! closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions