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
Should: Used Open-Ended List of Values (x-extensible-enum) Instead of Enumerations [112]
Enumerations are per definition closed sets of values, that are assumed to be complete and not intended for extension. This closed principle of enumerations imposes compatibility issues when an enumeration must be extended. To avoid these issues, we strongly recommend to use an open-ended list of values instead of an enumeration unless:the API has full control of the enumeration values, i.e. the list of values does not depend on any external tool or interface, and
the list of value is complete with respect to any thinkable and unthinkable future feature.
To specify an open-ended list of values use the marker x-extensible-enum as follows:
deliver_methods:
type: string
x-extensible-enum:
- parcel
- letter
- email
In OpenAPI 3.x does this have any advantages (apart from perhaps readability) over the more JSON-schema recipe:
deliver_methods:
type: string
anyOf:
- enum:
- parcel
- letter
- email
- {}
? 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:
```
accountType:
type: string
enum:
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: https://github.com/zalando/restful-api-guidelines/issues/412
@JonKohler from the documentation you linked to (emphasis mine):
For this reason, enums are not automatically turned into strongly typed enum types - instead they are rendered in the documentation comments for the property or parameter to indicate allowed values. To indicate that an enum will rarely change and that C#/Java enum semantics are desired, use the x-ms-enum exension.
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 (enum value descriptions notwithstanding) not an issue with the spec itself.
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: https://github.com/Azure/autorest/issues/2950
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?
There is obviously some demand to enhance enums in the ways you mention. Making them extensible (without using a registry approach) can be done using the anyOf syntax above. Tooling support for it would be up to individual vendors. Everything else will be considered as with any proposal for the spec, with the usual 'no promises' caveat.
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 3.1.0.md or 4.0.0.md branch/file to target the PR against. This is due to a number of factors including human bandwidth and not yet having tools to ensure patch changes always flow into the next minor version and minor changes flow into the next major version (effectively we would need to cherry-pick commits across branches but apply them to different files). Also creating a (say) 3.1.0 version of the spec would inevitably lead to questions about when it would be released, which are not always easy to answer.
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 const with single-element enum for draft-04) is:
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 oneOf + const + only title or similar annotations (there is a formal notion of "annotation" in newer drafts) is easily detectible and is expected to form a major basis for generative JSON Schema vocabularies (code generation, UI generation, etc.)
@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:
type: string
anyOf:
- const: foo
title: The Foo Thing
- const: bar
title: The Bar Thing
description: There's some explanation about the bar thing
- {}
right? But unless I'm missing something, wouldn't this not be sufficient because if the value "bar" showed up, we couldn't know whether it's a member of the "The Bar Thing" singleton type (and thus has the semantics of its description) or whether it's just any old string that corresponds to the third case of the anyOf? So the descriptions have no effect? In which case we would actually need to do something like:
type: string
oneOf:
- const: foo
title: The Foo Thing
- const: bar
title: The Bar Thing
description: There's some explanation about the bar thing
- not:
anyOf: ["foo", "bar"]
If we scale this up with more cases or a more complex base type than just string it does feel like it would get quite unwieldy and harder for parsing tools to detect the 'enum pattern' to me, so if this is all the case then it would be quite nice to have native support for extensible enums in JSON Schema/OpenAPI short-handing it.
(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" oneOf, but eh I dunno it feels like leakage to me having that closed version centrally defined?)
@adamjones1 I would use an anyOf since the const values ensure that it behaves mostly like a oneOf. At that point, you just need to figure out if the instance only matched the empty schema or if it matched one of the const schemas as well.
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. title and description) by specifying an output format for collecting the values of such keywords that apply to each instance location, and where those values came from in the schema.
So you could rely on matching title, but an even better option would be a keyword such as extendedEnumPlaceholder or something like that (I just made up that name, don't take it too seriously). This would be used something like:
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 false value in your annotation results, it matched a pre-defined option. If you only see a true value, it only matched the otherwise-empty schema option.
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
type:
type: string
anyOf:
- enum:
- PRODUCT_ARRANGEMENT
- OFFERED_ARRANGEMENT
- {}
Most helpful comment
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.