-
Notifications
You must be signed in to change notification settings - Fork 210
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
Populate the discriminator property for derrived types. #4618
Comments
Hi @greg-ww |
The request body takes an array of a base type, the base type has a discriminator mapping similar to below.
|
These values appear to be used in the generated code for deserializing the models but not when serializing them. I was wondering if this is an intentional design choice. |
Any chance you can share the schema of the derive type? Ideally, the microsoft.graph.managedIOSLobApp:
allOf:
- $ref: '#/components/schemas/microsoft.graph.managedMobileLobApp'
- title: managedIOSLobApp
required:
- '@odata.type'
type: object
properties:
....
....
'@odata.type':
type: string
default: '#microsoft.graph.managedIOSLobApp'
description: Contains properties and inherited properties for Managed iOS Line Of Business apps.
x-ms-discriminator-value: '#microsoft.graph.managedIOSLobApp' The code generated would then have it set in the constructor similar to |
I was kind of hoping this could be treated as a serialization concern in C#. When you deserialize a list of a base type you use the discriminator mapping to determine the derived type to use, when serializing to a list of a base type you set the discriminator value based on the mapping. Would save people having to add stuff to their Open API spec just to get the discriminator to work automatically when all the information needed is in the mapping. |
I also found some other issues while looking for a work around for this. In .Net setting a default value works but to support type narrowing in TS we wanted the discriminator value to be hard coded on the derived types. (For context the typescript team I am supporting isn't using Kiota as their generator). Since OpenAPI.NET(https://github.com/microsoft/OpenAPI.NET) doesn't yet support const values I settled for defining the discriminator property as having an enum with only one type. This works well for the typescript clients giving them a hard coded value. However in the .Net client I generate with kiota the single value enum appears to have to effect at all, it would be great if this also hard coded the value. Should I make another issue for this request? Additionally to work around this I tried adding both a default value to support the Kiota .Net client and an enum with only one value for the TS client, unfortunately this generates code that doesn't compile. Weirdly giving it a default value that matches the only value in the enum makes it try to assign an enum type to my string discriminator property. Should I make another issue for this also? I can provide simplified example open api specs in json that show case these two other issues. |
|
I believe the issue here is that the base has a type that is a string while the derived instances have the enum declaration. This causes a conflict by setting set the default as an enum while the type information from the base is a string. |
Am I mistaken in thinking that restricting the values for inherited properties in derived types using "enum" is valid in the Open API spec? |
As the property is defined in the base type and redefined in the derived type, the type of the base would be a string while the derived types would have the properties be inferred to be enums. Furthermore, since the schemas are inlined, Kiota would generate different enum types models for each derived type property which would conflict and cause an error. You would need to have consistency in the typing down the inheritance by either.
{
"openapi": "3.0.0",
"info": {
"title": "Polymorphic API",
"version": "1.0.0"
},
"paths": {
"/polymorphic-list": {
"post": {
"summary": "Accepts a list of polymorphic types and returns a list",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/BaseType"
}
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/BaseType"
}
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"BaseType": {
"type": "object",
"properties": {
"$type": {
"$ref": "#/components/schemas/TypeValues"
}
},
"required": ["$type"],
"discriminator": {
"propertyName": "$type",
"mapping": {
"A": "#/components/schemas/A",
"B": "#/components/schemas/B"
}
}
},
"A": {
"allOf": [
{ "$ref": "#/components/schemas/BaseType" },
{
"type": "object",
"properties": {
"$type": {
"$ref": "#/components/schemas/TypeValues"
}
},
"required": ["$type"]
}
]
},
"B": {
"allOf": [
{ "$ref": "#/components/schemas/BaseType" },
{
"type": "object",
"properties": {
"$type": {
"$ref": "#/components/schemas/TypeValues"
}
},
"required": ["$type"]
}
]
},
"TypeValues":{
"type": "string",
"enum": ["onlyValue", "alternativeValue"],
"default": "onlyValue"
}
}
}
}
|
@andrueastman You seem to be explaining how Kiota does not support this use case, I am more interested in discussion of if it should support it. Enums are not types in the OpenAPI spec, I do not believe there is anything inconsistent about the typing of my property in OpenAPI. I am under the impression that my spec is valid (although admittedly not designed with the sole focus of making Kiota generate compiling code). If my spec is valid (in the eyes of OpenAPI) should Kiota be able to support it? |
@greg-ww Thanks for raising this issue and providing the details. I have a few thoughts.
@andrueastman What do you think about special casing enums with one value to be a const of the type defined in the schema? That would avoid the problem you describe of base classes redefining the type in derived classes. |
I'm also having this issue, but I am using enum as a discriminator. The workaround proposed in #4618 (comment) (@andrueastman ) won't work unfortunately as it sets 'onlyValue' as a default value for every type and I would need to have 'onlyValue' as a default for 'A' type and 'alternativeValue' as a default for 'B' type. |
Hey everyone, One feature improvement we've already mentioned on this thread: const support. This depends on 3.1 support by OAI.net and integration of the changes here. Let's table that for later. (if one of you wants to create an issue specifically about that so we don't forget, please go ahead) Another improvement we eluded to would be to "ignore the enum information when the property is a discriminator" so the deduplication logic doesn't kick in, and we consider it a "basic string value used for discrimination". Does that make sense? I believe that if we address this later point, and assuming the property documents a default, we should address the initial ask for serialization. Thoughts? |
supporting enums for discriminators: this should be possible with the serialization/deserialization code we have in place. Including with defaults. It'd just require more work overall. setting the discriminator value in the parent serialization: I'm not sure we want to do that. Not only this is going to require type testing (not possible in some languages/overly complex), but also this should be unnecessary assuming the default value is set in each derived type. Does that make sense? For the people involved on this thread. From a purely functional perspective, what would be preferred? supporting enums for discriminator? or ignoring enums and always using strings? |
Personally, I'd like to be able to use enums as discriminators. |
The problem with putting the onus on the Open API spec to specify default values for the discriminators is that Kiota isn't the only client generator people might be using, assigning default values to enums might also break other clients who didn't think to cover that use case or who need their own contradictory work arounds. If Kiota could handle it as part of serialization / deserialization it would avoid creating more hoops for the spec to jump through and improve compatibility with other generators, meaning no matter what other client generators our consumers use we always support Kiota. In my opinion the goal should be to make it so we never have to add anything beyond the discriminator mapping to our spec for this. |
On enums for discriminators I do not have strong opinions. I do think that an enum with only one value listed should be treated as equivalent to const though. |
Thanks for the additional input. I think a first stopgap would be to "ignore" enum information if the property is a discriminator. This should unblock the original issue here. And we can later on see whether there's additional demand to support enums in discriminators. It'll also reduce the work that needs to be done on the topic. As for setting the default for the discriminator property I believe this is already done by kiota today. There might be some side effects with the backing store though. |
@greg-ww @MateuszMaleckiAnsys is one of you willing to submit a pull request for the first part of my last message? |
Is your feature request related to a problem? Please describe the problem.
I could be doing something wrong here but I couldn't find any documentation on sending heterogeneous collections in a post, only on receiving them. I have an endpoint that takes a list of derived types, the open API spec defines the discriminator property and the mappings for the derived types. The models for the derived types that Kiota generates have a Type property I can assign the correct value to but by default it is empty.
Client library/SDK language
Csharp
Describe the solution you'd like
Since the desired value for these types is constant and defined in the open API spec I don't understand why I need to set it when working with these models. Can it not just be hard coded to the correct value?
Additional context
It's possible there is something wrong with my open API spec but I couldn't find any confirmation in the documentation of what the desired behavior is for this use case is.
The text was updated successfully, but these errors were encountered: