-
Notifications
You must be signed in to change notification settings - Fork 9.1k
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
Extensible enumerations (growable lists) #1552
Comments
In OpenAPI 3.x does this have any advantages (apart from perhaps readability) over the more JSON-schema recipe:
? Thanks for citing the Zalando extension, BTW, that's useful and interesting. |
I'll vote for extensible enumerations. However, it would be useful if the enumerated values were resolvable. This allows a client to "discover" the meaning of an unknown value. If the client is semantically aware, and the value resolves into an ontology, then the client may even be able to process the value based on its' advertised semantics. |
bump! |
Alternatively, the proposal set out my the Microsoft Azure team, here: https://github.com/Azure/autorest/blob/master/docs/extensions/readme.md#x-ms-enum IMHO is pretty good, and gives even more flexibility:
|
I've reached out to the Zalando team to see if we could parlay a single definition, and perhaps help the openapi community model out a proposal for upstream, here: zalando/restful-api-guidelines#412 |
@JonKohler from the documentation you linked to (emphasis mine):
Which seems to be the opposite way around to the intent of this issue? It seems the problem here is lack of consistency and flexibility in two or more code-generation tools and ( |
Thanks for the sanity check @MikeRalphson - Let me touch base with the Azure team to see if we can get some consensus on this. In short, if we boil this back to the need to have both extensible enums as well as having some metadata about those enums (description, etc), then that is a good thing to focus on for some modification to the upstream spec. Is that fair to say? or is my understanding off course? |
@MikeRalphson - I've posed this to the Azure team, here: Azure/autorest#2950 |
There is obviously some demand to enhance |
Thanks @MikeRalphson ... since this is my first interaction with doing an upstream proposal for the spec, im happy to spearhead this. Is there any guidance on how to formally propose something to the spec? I checked out the readme on this repo, and it seems like making a thread is the way to go (here we are), but I wanted to see if perhaps there is a more structured way, to make your life and everyone elses easier? I'd hate for this good conversation to get locked up in a long GH thread |
@JonKohler the short answer is that the spec. is just markdown and anyone can, and is very welcome to, PR changes against it. Though a PR could just be a 'straw-man', judging when an issue has enough consensus behind it to take it to a PR is definitely an art rather than a science. A longer answer is that this is something I personally feel we struggle with today, partly because we don't want to waste anyone's time on a change which may have to undergo several revisions and still possibly not make it in, and also because if the change would need to target a minor or major semver version of the spec (as any change apart from wording/examples etc would) then we don't currently have a That said, one really good way to contribute is to participate in the (usually) weekly TSC web calls. Agendas are created as GitHub issues and details for joining are in the README. |
@JonKohler Take a look at the Draft Features section of Development.md. This is a new process for test-driving proposed features prior to making them a formal part of the spec. |
FYI, for value / title or description pairs the official JSON Schema recommendation (using draft-06 syntax, replace oneOf:
- const: foo
title: The Foo Thing
- const: bar
title: The Bar Thing
description: There's some explanation about the bar thing An extensibility proposal based on this will fit well with newer drafts of JSON Schema. The |
@MikeRalphson @handrews If we wanted to combine these two features in the code samples you gave, and have an enum which is both open and has descriptions on its members, the naive way of doing it would be something like:
right? But unless I'm missing something, wouldn't this not be sufficient because if the value
If we scale this up with more cases or a more complex base type than just (You could remove duplication in OpenAPI at least by defining the closed version of the enum as a schema and then having the overall schema reference it in an "either this or not this" |
@adamjones1 I would use an OAS 3.1 will update to the latest draft of JSON Schema which supports modular extension vocabularies (this is a totally new thing since my last comment from 2018). In the time since the draft of JSON Schema that was used for OAS 3.0, we have improved support for annotation keywords (e.g. So you could rely on matching type: string
anyOf:
- const: foo
title: The Foo Thing
extendedEnumPlaceholder: false
- const: bar
title: The Bar Thing
description: There's some explanation about the bar thing
extendedEnumPlaceholder: false
- extendedEnumPlaceholder: true If you see a |
Any update on on how to do it in openapi 3.0. Is this the way to go for extensible enum in opanAPI 3.0
|
Any decisions on this? |
Dummy string variant can be modeled as
Client should support this variant to maintain forward compatibility. Server should not allow this variant on deserialization / semantic validation layer. And an enum can be represented as an alternative between two subtypes
|
@DXist I'm trying to get this to work. The tricky thing is that string values through an API are non-breaking unless you have a client that tries to serialize them as a generated enum model and doesn't have a value that was added. So the openapi spec turns generated (and We have a spring boot kotlin app and adding this over an enum doesn't really do the trick for the client generators:
The result is just a typical enum generation being done. The ideal result would generate classes that don't explode when an unknown value is passed in. Similarly, running the kotlin-spring server generator on this gives a class like so:
Which isn't the most useful generated code. Would be pretty nice to have an option for generated code that allows default on unknowns: eg:
|
@thejeff77 this sounds more like a problem with the code generation tool not understand the schema than a problem with the schema. |
@DXist I second @handrews comment. You can implement a fallback for unknown enum values received from the API at the client level. This is actually exactly what openapi-generator does. Most implemented languages in openapi-generator support a I do agree that it would be nice to have a standard way of defining this fallback in the OpenApi specification itself, vs hard-coding it in a specific client SDK, for tool interoperability's sake. |
@dpashkevich this is more a JSON Schema thing than an OpenAPI thing, so such a keyword could be implemented as an extension vocabulary (OpenAPI itself implements a few additional keywords as a JSON Schema extension vocabulary). Tooling vendors would have to adopt the vocabulary, of course, but it would not require an update of either OpenAPI or JSON Schema to do so. |
Yes, I understand that there's always an option to use a vendor extension, but it would be great to eventually promote it to an official standard, if it's deemed universally useful. This whole github issue discusses a gap or limitation in the OpenAPI/JSON Schema standard in expressing whether an enum can grow in the future or not. |
@dpashkevich my point is that people can take action now, and in doing so can demonstrate the usefulness and suitability of a proposal. We don't have to just debate it in purely theoretical terms and wait for the next big release. There have been other keywords that started as extensions, but now there's an actual mechanism for managing extensions and asserting that they are required in order to process a particular schema. That wasn't present before. So experimentation and implementation are a bit easier now. JSON Schema vocabularies are intended to be more interoperable than simply being vendor-specific extensions. They are identified by URIs and can be recognized that way across implementations, rather than just having an |
@handrews I think if I'm reading your point correctly - we can add the support for default-if-unknown in specific client generators to demonstrate the usefulness and suitability of it before debating it as a more general keyword? If that sounds right (correct me if I'm missing something) - I'm wondering - what needs to happen before this crosses the bounds of "purely theoretical" into common use of an extension that ends up as a global keyword? Because as @dpashkevich is pointing out, this is already there in most generators. Which to me suggests it's been proven out as useful, combined with this thread about the more global issue of enum declaration needing to be extensible or non-breaking somehow needing a more general solution. Of the ones I've found (only looked for a little while) are here:
An extensible-enum possibility seems more theoretical per @handrews 's point.. this seems to have more pitfalls around being pragmatic and makes the definition and codegen a bit more complex to swallow. Whereas adding an option to not break API consumers when string values are added to auto-gen'd enums - this prevents client issues more globally, and has been proven out to a larger extent in the community. Although this all might be in the wrong context because this option is a generator option, not an option that's put in the openapi spec itself... |
@thejeff77 someone needs to write up the spec for the keyword(s) involved, assign a URI to the vocabulary, publish it (somewhere, anywhere) so that people who want to use it can declare it in You can make a pull request here once you have a vocabulary specification if you want more people to see it. |
I think the need for declaring Rather than handling an unknown value by defaulting to a predefined constant (often, e.g., For an example of this approach, see how the AWS Java SDK v2 handles exposing an enum-backed property for ChecksumAlgorithm. The generated object has two property accessors:
This way clients get to benefit from enums in the happy case, but still have a way to fetch or supply raw data for an unrecognized value without having to update their software version. If the OpenAPI tooling took a similar approach, then there wouldn't be a need to define Lack of this support in OpenAPI has led me to declaring properties that should be enums as strings, and then declaring app-local enum conversions, losing the benefit of a shared spec. |
We would love to see such option in openapi specification. We know that there is Any chance it could be picked up for standard definition? |
😥 here we may miss the user experience , of the API designer as well as the Tooling implementer for sure we may handle it via anyOf / oneOf , and const keyword with description , but enum has been created to be a short cut to this complexity , same around extensible enum , it s a real world case, that would need to be tackle in an easy way . Then that is may be not a OAI topic rather than a Json Schema |
Ok I've been part of this discussion for a while, and am going to write up some specifications per @handrews guidance. First, I'll summarize our discussions:
Second, I'll propose here first, for further discussion:Current enum schema definition example looks like the below, supporting a "default" key for when it may be null. As it relates to enums, referencing the fixed-fields definition, "If the enum is defined, the value MUST exist in the enum’s values." Existing Enum OAPI Definition Example "DirectionEnum" : {
"type" : "string",
"enum" : [ "FORWARD", "LEFT", "RIGHT", "REVERSE" ]
"default": "FORWARD"
} Proposed Enum OAPI Definition Example The proposal is to add a key This is meant to solve the tolerant-reader problem, as a value that does not map to an enum causes the parsing to break. This solution will allow the API creator to purposefully opt-in to using a value that exists in the enum array when the value does not exist within that array. Example: "DirectionEnum" : {
"type" : "string",
"enum" : [ "FORWARD", "LEFT", "RIGHT", "REVERSE", "NOT_MAPPED" ]
"default": "FORWARD"
"fallback": "NOT_MAPPED"
} ExamplesThis pattern has been implemented as a client generator option in many clients today, and has been a long-sought after feature for openapi to support in some standardized way. Of the ones I've found are here: OpenAPITools/openapi-generator#10038 Note that Jackson treats the default the same as a fallback in its @JsonEnumDefaultValue annotations indicating the default value, however it seems somewhat unlikely that OAPI community would rather change their definition of default as it pertains to schema than support a new key, however I'm open to feedback about this. |
@thejeff77 Excellent write up. My main concern with the proposal is that we're saying it would be too difficult to force a non-spec-based standardization across the few dozen of generators. That's fair and I can imagine the difficulty there. But in turn we're proposing a spec-based convention that thousands of developers will now need to become aware of and retroactively add to their existing specs. I see a few problems with this:
All things considered, I think a tool-based convention is the cleanest long-term solution here, but I respect the desire to find something more tractable. This remains a severe paint point for anyone who uses enums in their APIs. Could the OpenAPI team perhaps help drive a tool-based convention/improvement here? |
@Bennett-Lynch thanks for the feedback. Unfortunately what I'm hearing here (or not hearing here) is that there is no such thing as a tool-based convention. If it exists, what is it? How is this done and what is an example of it being done prior? Any spec improvements will likely be a lot of work and have some of those downsides for sure. So we'd want the right proposal. As far as OAPI standard json proposals, I can think of two others that may work.. strictDefault: true|false, or perhaps changing the definition of default to be tolerant for schema enums. As far as preventing bad api design.. personally I believe this is not the OAPI specification's job. Assuming an english all uppercase UNKNOWN is always the best value here may be presumptuous of us. But maybe not? With a flag like strictDefault: false, the tolerant reader could use the default if the value does not exist in the enum.. then specifying another value would not be required. I can maybe write this up too if anyone likes that better |
@thejeff77 , as part of the discussion there was also a point about having the capability to have for enum a per value description that is currently a pain. it was mentionned leveraging x-ms-enum like |
Hey all,
I did some searching in the OAI repo, and it didn't jump out at me as an existing feature request.
The issues with enum being "non-growable" without making a major semver change for an API have been talked about in several places. Zalando came up with nice framework within their API guidelines to handle this, which would be incredibly useful to upstream into the specification itself
https://zalando.github.io/restful-api-guidelines/#112
The text was updated successfully, but these errors were encountered: