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

Support oneOf inheritance for code generators #13

Open
RicoSuter opened this issue Dec 19, 2015 · 13 comments
Open

Support oneOf inheritance for code generators #13

RicoSuter opened this issue Dec 19, 2015 · 13 comments

Comments

@RicoSuter
Copy link
Owner

RicoSuter commented Dec 19, 2015

https://raw.githubusercontent.com/fge/sample-json-schemas/master/geojson/geometry.json

Branch: one-of-inheritance

@RicoSuter
Copy link
Owner Author

See also: #302

@LeroyK
Copy link

LeroyK commented Nov 7, 2019

A combination of oneOf with allOf almost seems to work, except that the client code generator uses the first reference from the list of oneOf references to generate (C#) client code. It should select the base schema if all oneOf references contain a single reference to that base schema in their allOf list.

Example schema:

{
  "openapi": "3.0.1",
  "info": {
    "title": "Pet API",
    "version": "2019-11-06"
  },
  "paths": {
    "/pet": {
      "get": {
        "tags": [
          "Pet"
        ],
        "operationId": "GetPet",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Dog"
                    },
                    {
                      "$ref": "#/components/schemas/Bird"
                    }
                  ],
                  "discriminator": {
                    "propertyName": "discriminator"
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Bird": {
        "required": [
          "wingspan"
        ],
        "type": "object",
        "allOf": [
          {
            "$ref": "#/components/schemas/Pet"
          }
        ],
        "properties": {
          "wingspan": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "Dog": {
        "required": [
          "barks"
        ],
        "type": "object",
        "allOf": [
          {
            "$ref": "#/components/schemas/Pet"
          }
        ],
        "properties": {
          "barks": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "Pet": {
        "required": [
          "birthDate",
          "discriminator"
        ],
        "type": "object",
        "properties": {
          "discriminator": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "birthDate": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "discriminator": {
          "propertyName": "discriminator"
        }
      }
    }
 }
}

Generates in (Dog instead of Pet).

System.Threading.Tasks.Task<Dog> GetPetAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));

@LeroyK
Copy link

LeroyK commented Nov 7, 2019

The following code fixes the above.

if (OneOf.Count > 1 &&
    OneOf.Select(x => x.GetActualSchema(checkedSchemas)).ToList() is var oneOfActualSchemas &&
    oneOfActualSchemas.All(x => x.AllOf.Count == 1) &&
    oneOfActualSchemas.Select(x => x.AllOf.FirstOrDefault().GetActualSchema(checkedSchemas)).Distinct().ToList() is var potentialBaseSchemas &&
    potentialBaseSchemas.Count == 1)
{
    checkedSchemas.Add(this);
    return potentialBaseSchemas[0];
}

If you add it here:

@shadow-cs
Copy link
Contributor

@RicoSuter question (I just want to be extra clear on the matter): NJsonSchema by-design does not adhere to JSON Schema specification for allOf validation right (see here)? This is intentional since the primary goal of NJsonSchema is to support allOf inheritance as specified by the OpenAPI.

If the above statement is true, may I suggest adding a note to Inheritance wiki page? With a link to this issue. Might help newcomers figuring this stuff out. Thanks.

@RicoSuter
Copy link
Owner Author

NJsonSchema by-design does not adhere to JSON Schema specification for allOf validation right

I'd say yes... So ideally we should have an option: #302

I think the validators work as expected but if you generate a schema from C# types it will not generate a JSON Schema which works with validation but which works with OpenAPI as this is the primary use case of NJS.

But it makes sense to have an option to choose between OpenAPI inheritance and JSON Schema validation inheritance which would not work with OpenAPI.

If the above statement is true, may I suggest adding a note to Inheritance wiki page?

Yes, please update the wiki if it makes it clearer for other people.

@shadow-cs
Copy link
Contributor

Yes, please update the wiki if it makes it clearer for other people.

Added a note hope it's clear enough...

@RicoSuter
Copy link
Owner Author

Ideally we add OpenAPIs inheritance mapping and discriminator to the validator so that this is also supported.. shouldnt be too hard to add

@niikoo
Copy link

niikoo commented Feb 24, 2021

+1

@hideintheclouds
Copy link

Any news regarding this?

@wilkovanderveen
Copy link

What is the status of this issue? I am using mulesoft anypoint exchange which generated oas2 specs and converted these to OAS3, but the 'oneOf' issue is still here.

@dauthleikr
Copy link

dauthleikr commented Feb 19, 2023

Any movement on this?

Edit: In case anyone also cares about this: I did a dirty "fix" that just uses object (or whatever your AnyType is) as the type instead of the first possible type. To me that is preferable, because now I can just implement a JsonConverter and serialize/deserialize based on some discriminator. Ideally you'd want a base class to be used, but that's not always possible so ¯\(ツ)
https://github.com/dauthleikr/NJsonSchema

I don't think this should be merged here, there are way better solutions. This just allows workarounds for the meantime ...

@IIphynixII
Copy link

@RicoSuter Are you looking into this at the moment?

@rhermans2004
Copy link

Would really like to see the oneOf way for inheritance added as option to generate schema (from code). Probably extension with unevaluatedProperties is also needed to make this work, as described in JSONSchema. I tried the flattenHierarchy, but that still seems to require such a oneOf construct.

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

No branches or pull requests

9 participants