-
-
Notifications
You must be signed in to change notification settings - Fork 7k
[Go] Support polymorphic substitution ("subclasses") #4559
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
Comments
I've noticed the same problem occurs in the generated Python client. |
Another possibility to solve this is to use struct embedding. I've seen this used in other go based swagger generators such go-swagger. Could be a simple enough approach to solve the issue... |
Are you referring to the following: if type B has "allOf" type A (and potentially other properties), then go struct B embeds go struct A? If so, yes, this would be great to have better modeling of inheritance, as opposed to flattening all structs. But I'm not sure how this will address the use case I have raised here. I'll open a separate issue to support inheritance with embedded structs. |
openapi.generator does not play well with discriminator(s) from the openapi spec. related issues: OpenAPITools/openapi-generator#4559 OpenAPITools/openapi-generator#417 the api_ldap_identity_providers.go is a copy/paste search and replace of api_identity_providers.go to return LdapProviders instead of sub stub IdentityProvider we need to do the same for the identity provider types. Signed-off-by: Daniel Nilsson <[email protected]>
For polymorphism in golang interfaces are required. Embedding of interfaces and/or data structures is optimization to not repeat the code in multiple places. Struct types in golang regardless of the use of embedding do not have polymorphic behavior i.e. you cannot use a struct embedding a "base" struct as parameter or result of function declared to accept/return the "Base" struct. The topic of go and json polymorphism is not a simple one and I have only found partial solutions. To build a holistic solution required putting all these together and then solving couple of riddles. I came up with a write up on the topic as I think it will be really helpful for openapi-generator and other tools to support polymorphism. I cannot help with the implementation as I do not understand well enough the project but I hope this write up is inspiring. |
Uh oh!
There was an error while loading. Please reload this page.
Description
This is a suggestion to generate go interfaces in the go code, or some other mechanism to support sub-classes.
The OAS spec supports polymorphism and inheritance. One area that seems to be problematic in the generated go code is when a schema refers to a type that has multiple sub-types, and the actual sub-type is determined at run-time by the api service. The go code is generated with a pointer to a struct (not an interface), which means there is no possibility of dynamically determining the proper go struct based on the discriminator value.
For example, suppose an OAS API specifies a path that returns a heterogenous list of animals. The returned list may include dogs, cats, and any "subclass" of animal. The api service may return a list of animals, and each object in the array may have a different discriminator value (e.g. Dog, Cat). This scenario can also apply to a component: for example, the Animal type may have a property which specifies a list of visited places, and each "Place" may have sub-types. A place could be a city, country or other types of places.
With the OpenAPITools generated code, the go client will unmarshal the list of Animals into the "Animal" go struct, and it will lose all the properties that were specified in the sub-types (such as Dog and Cat).
To address this problem, we have created a custom go implementation, and we generate a golang interface for each specified type in a OAS schema. The go type of the generated property is the (generated) go interface, not a pointer to a go struct. This makes it a bit harder to unmarshal because the default go unmarshaler does not know which type to instantiate. But this can be handled with a custom, generated JSON unmarhshaler; the unmarshaler reads the value of the discriminator property to determine the actual type, then it instantiates the proper go struct (e.g. Dog or Cat).
When there is a small and fixed number of sub-types, one could argue "oneOf" should be used to provide an explicit list of all sub-types. Besides the fact that currently the generators do not handle oneOf, it would ugly when the number of sub-types grows to a large value.
Is there a strong reason to generate pointers to go structs as opposed to go interfaces? Are there other approaches that work for polymorphic substitution? It seems the OAS spec is not very clear on that topic.
openapi-generator version
4.2.1
OpenAPI declaration file content or url
Command line used for generation
Steps to reproduce
Related issues/PRs
OAI/OpenAPI-Specification#403
Suggest a fix
The text was updated successfully, but these errors were encountered: