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

Integer enum with named items #681

Closed
kenjitayama opened this issue May 5, 2016 · 45 comments
Closed

Integer enum with named items #681

kenjitayama opened this issue May 5, 2016 · 45 comments

Comments

@kenjitayama
Copy link

I would like to propose a new field called enumNames.

Example:

definitions:
  weather:
    type: object
    required:
      - type
    properties:
      type:
        type: integer
        format: int32
        enum:
          - 1
          - 2
          - 3
        enumNames:
          - Sunny
          - Cloudy
          - Rainy

This information is necessary for generating the following Java enum.

public enum Weather {
    Sunny(1),
    Cloudy(2),
    Rainy(3);

    private final int type;

    private Weather(final int type) {
        this.type = type;
    }

    public type getType() {
        return type;
    }
}

Some web APIs require clients to send/retrieve integer enum items while knowing what they mean. So it is useful to be able to generate this kind of enum.

I had been seeking advice in the following swagger-codegen issue, and got a conclusion that we need a vendor extension (which corresponds to this proposal) using Swagger 2.0 spec.
swagger-api/swagger-codegen#2690

@ePaul
Copy link
Contributor

ePaul commented May 6, 2016

@webron
Copy link
Member

webron commented May 19, 2016

It's not related to json-schema-org/json-schema-spec#348, it's a duplicate for it.

@webron webron closed this as completed May 19, 2016
@kenjitayama
Copy link
Author

@webron
json-schema-org/json-schema-spec#348 is talking about documenting each enum items, rather than assigning names to enum items (this issues topic).
So I think this issue is not a duplicate.

@webron
Copy link
Member

webron commented May 19, 2016

Fair point, missed that.

@webron webron reopened this May 19, 2016
@ralfhandl
Copy link
Contributor

I like this, combined with json-schema-org/json-schema-spec#348:

type: integer
format: int32
enum:
 - value: 1
   name: Sunny
   description: Blue sky
 - value: 2
   name: Cloudy
   description: Slightly overcast
 - value: 3
   name: Rainy
   description: Take an umbrella with you

If the names should be unique (probably a prerequisite for code generation) a hashmap would be more appropriate:

type: integer
format: int32
enum:
  Sunny:
    value: 1
    description: Blue sky
  Cloudy:
    value: 2
    description: Slightly overcast
  Rainy:
    value: 3
    description: Take an umbrella with you

So enum could either have an array value with just the list of values, or an object value with named and potentially further annotated values.

@webron
Copy link
Member

webron commented May 19, 2016

Well, either the name or the value has to be unique, doesn't matter which one as long as the intent is clear.

However, where does it end? Just a single value? Technically in Java (referenced in the original comment) allows setting any number of properties for enum values. What about types? There's no indication it's an int, it could be a string a string as well. Should that be inferred? Are we supposed to introduce a big construct to support all these options? Also, I have no idea what other languages support and how it would affect them.

And last but not least, if I just want to define a basic enough, would I have to end up with something like:

enum:
  Sunny: {}
  Cloudy: {}
  Rainy: {}

That's...

@wparad
Copy link

wparad commented May 19, 2016

This feels like a leaking of implementation details in the API, seemingly no different then describing every possible combination of values for a proper object's properties. I suspect it is the result of attempting to use the standard to automatically create an sdk for functional calls, in which enums are being semantically defined and maintained here. To me, enums are an object-type not a value-type and thus shouldn't get any special treatment.

@kenjitayama
Copy link
Author

Now I think @ralfhandl's former format is best.

  1. ralfhandl's former fomat
  2. ralfhandl's latter format
    • This makes assigning a name a requirement, which may be too much of a breaking change?
    • I think the uniqueness of names doesn't have to be baked in to the format. The OAI spec can specify that.

For webron's comments…

Well, either the name or the value has to be unique, doesn't matter which one as long as the intent is clear.

I think both should be unique and should be written in the specs.

However, where does it end?

I don't feel the number needs to be limited.

What about types?

Value types of enums are specified since Swagger 2.0, like this:

type: integer
format: int32
enum:
  :

(Looks like only strings were allowed in 1.0)

For wparad's comments…

I consider "naming enum items" is a missing spec in Swagger 2.0. In general, for an enum to be an enum, each item should have an name.
According to wikipedia:

In computer programming, an enumerated type (also called enumeration or enum, or factor in the R programming language, and a categorical variable in statistics) is a data type consisting of a set of named values called elements, members, enumeral, or enumerators of the type.

@ePaul
Copy link
Contributor

ePaul commented May 20, 2016

@webron The name (if there is one) needs to be unique in the target programming language. The value needs to be unique "on the wire". But the value is not necessarily a string, it can be anything (string, number, boolean, object, array). Therefore using the value as a keys in a map / property names in an object doesn't really work.

@webron
Copy link
Member

webron commented May 20, 2016

I wasn't advocating the map option, just picked one of the two.

I'd like to clarify that the limitations for the enum declarations are derived from JSON Schema - we did not introduce any special restriction there.

Also, unlike what @kenjitayama mentioned, the type is not derived from the type mentioned in the encompassing definition - again, that's the way JSON Schema works.
For example:

type: string
enum:
  - 1
  - 2
  - 3

doesn't mean that "1" is the valid value - it means that nothing will validate against that schema, because none of the enum values are strings.
Regardless, I was referring to the types of additional values for names enums, not the 'root' values. For simplicity, if we do provide a solution we may limit it to just one value.

There are two problems to breaking away from the current structure:

  • None of the existing JSON Schema validator could handle it, so customized tooling is required - this may hinder adoption.
  • The constraint to require both the names and values to be unique couldn't be enforced by the (meta) JSON Schema and will require external validation.

@kenjitayama
Copy link
Author

I'm not sure I understood what webron said about types, but I found that Swagger 2.0 uses JSON Schema Draft 4 (the latest) and enum spec is derived from it.
Looks like it's for validation rather than for supplementing description of data type(so this issue's use case is out of the scope).

Next, I found these proposals for JSON Scheme v5

I wonder if one of this would be accepted, and if OpenAPI v3 will support JSON Schema v5. And when it would happen.

Other reference:

@webron
Copy link
Member

webron commented May 22, 2016

While we've yet to reach that point, it's unlikely draft 5 will be supported because it's not finalized. Even if finalized before finalization of 3.0, it's unlikely they'd be enough tooling around it for us to claim support of it. That said, if it's finalized before, it's easier to derive the structure from it and use it as well.

@kenjitayama
Copy link
Author

I see there's a long way to go.
But at least, now it is clear what is necessary to support this.

@zeroasterisk
Copy link

Is there any recommendation for how to define these possible values in the existing swagger specifications until this becomes supported?

@webron
Copy link
Member

webron commented Jul 21, 2016

Tackling PR: json-schema-org/json-schema-spec#741

@cosbor11
Copy link

+1

@khaosdoctor
Copy link

Is this still going on? Because it would help A LOT

@webron
Copy link
Member

webron commented Mar 14, 2017

Because this breaks away from JSON Schema, we've not included support for it in 3.0.

@khaosdoctor
Copy link

I saw some great suggestions on using something like:

enum:
  key: value

Along with using the common method. Is this valid yet?

@webron
Copy link
Member

webron commented Mar 14, 2017

Things haven't changed in the last 6 hours ;)

@josh-burton
Copy link

This is a problem for us too. Are there any hacky work arounds to make this work in the meantime?

@darrelmiller
Copy link
Member

@athornz Microsoft tooling uses the extension x-ms-enum

@rlabrecque
Copy link

It's been over a year since the last comments, has anything changed on this front? All proposed options would work for me.

@ghost
Copy link

ghost commented Nov 21, 2019

This is also an issue for C#. NSwag is currently generating the following for an enum because their is no support for name.

Generated Example:
public enum ObjectState
{
_0 = 0,
_1 = 1,
_2 = 2,
_3 = 3
}

Generated Code should like the following:
public enum ObjectState
{
Unchanged = 0,
Add = 1,
Update = 2,
Delete = 3
}

@BlackGad
Copy link

BlackGad commented Dec 2, 2019

Face with same issue on NSwag client generation.

@handrews
Copy link
Member

handrews commented Dec 2, 2019

@BlackGad @Kevweir @rlabrecque @peol etc.

OpenAPI 3.1 is likely to move to JSON Schema draft 2019-09 (formerly known as draft-08) per PR #1977. That would allow the solution I showed above and allows for creating new re-usable JSON Schema vocabularies (sets of keywords) for specific purposes such as code generation. These can be formally identified so that different implementations can recognize and implement them (which was previously not possible in JSON Schema, or at least not in any practical way). So:

Here's an example with a totally fictional codeGen keyword that provides guidance on how to interpret the Schema Object in which it appears (see also Appendix E of the current JSON Schema Core specification for another example of how code generation keywords could be defined).

codeGen: namedEnum
oneOf:
  - const: 1
    title: Sunny
    description: Blue sky
  - const: 2
    title: Cloudy
    description: Slightly overcast
  - const: 3
    title: Rainy
    description: Take an umbrella with you

In this example, the codeGen keyword informs the generator that the Schema Object should be interpreted as a named enum. Presumably, the definition of how this keyword works would say something like "the namedEnum value, when it appears alongside of a oneOf where each branch of the oneOf contains a const and a title, indicates that the oneOf should be treated as a named enumeration, where const gives the value and title gives the name."

This way, we do not need to add more keywords that have an identical validation effect, which adds to the burden of validator implementations. Validators can safely ignore the unknown-to-them codeGen keyword and treat the other keywords as usual for validation purposes, while code generators get the additional information they need from the specialized keyword.

This is just one of many ways this (and other code generation problems) could be solved. Hopefully once OAS 3.1 is out (assuming draft 2019-09 JSON Schema support is indeed included) the OpenAPI community will use the new features to try out different ideas and converge on a standard code generation vocabulary. The advantage of OAS 3.1 + 2019-09 JSON Schema is that this process of producing a new vocabulary can happen independent of both the JSON Schema and OAS specification processes.

@xiaoxiangmoe
Copy link

xiaoxiangmoe commented Mar 10, 2021

@MikeRalphson @webron @darrelmiller OAS 3.1 was released,any update on this issue?

should we use codeGen: namedEnum?

@handrews
Copy link
Member

@xiaoxiangmoe I made up codeGen: namedEnum on the spot when writing that comment. A more likely approach would be a code generation vocabulary of keywords rather than a single codeGen keyword which would get very overloaded very quickly. I'm not aware of any such vocabulary, but now that OAS 3.1 is out and fully compatible with JSON Schema 2020-12, anyone (such as a tooling vendor) can create a vocabulary and work to get it supported in implementation without having to wait for a new version of OAS or JSON Schema.

It will obviously take a bit for JSON Schema vendors to add support for vocabularies (meaning, add the annotation output support and enable folks to write plugins to handle previously unknown vocabularies rather than just hardcoding all keyword support) and for OAS vendors to make use of that (meaning make use of annotations from JSON Schema to recognize codegen use cases).

So the solution is now possible in theory, but there are several things that need to be done before it's usable in practice.

@MarkRosemaker
Copy link

Note that if you take the json of an OpenAPI modal directly, without any modifications, and use it as the basis of your JSON Schema Form, you instantly have a nice looking form using all the information from the OpenAPI (title, description, format etc.) where the user can submit data. This way I make the latest developments of an API quickly available to my colleagues.

If this proposal is accepted, that would enable dropdowns where the enumNames are displayed but the underlying enums are in the payload.

My point is that the JSON Schema Form specification is exactly the same as OpenAPI except for this one thing and therefore, I fully support this proposal.

@handrews
Copy link
Member

@MarkRosemaker parallel arrays are horribly error-prone which is why the proposal as initially shown here has never drawn serious support within JSON Schema. The oneOf + some keyword that signifies to a generator tool (form, code, docs, whatever) to interpret that oneOf as a named/titled/whatever enumeration based on the const value in each branch avoids the parallel array problem and is in general much more flexible as you can include additional information, such as a help string to be extracted and associated with the value somehow.

@Tasselhoff
Copy link

Tasselhoff commented May 6, 2021

This is similar. I have several linked fields that could be each in a separate enum, but they go together (OK, system could be static, but code and display need to be linked):

          coding:
            type: array
            items:
              enum:
                - {system: http://terminology.hl7.org/CodeSystem/v3-RoleCode,code: _DedicatedServiceDeliveryLocationRoleType,display: DedicatedServiceDeliveryLocationRoleType} 
                - {system: http://terminology.hl7.org/CodeSystem/v3-RoleCode,code: _DedicatedClinicalLocationRoleType,display: DedicatedClinicalLocationRoleType} 
                - {system: http://terminology.hl7.org/CodeSystem/v3-RoleCode,code: DX,display: Diagnostics or therapeutics unit} 
                - {system: http://terminology.hl7.org/CodeSystem/v3-RoleCode,code: CVDX,display: Cardiovascular diagnostics or therapeutics unit} 

Is there a way to link two or more enum values like this? It doesn't give an error, but the enum values don't render in schema output. Also, the field names are fixed, I can't use "title" and "description".

@Tasselhoff
Copy link

Tasselhoff commented May 6, 2021

I've tried the following, but the enum still doesn't render:

          coding:
            type: array
            items:
              type: object
              properties:
                system:
                  type: string
                  default: http://terminology.hl7.org/CodeSystem/v3-RoleCode
                code:
                  type: string
                display:
                  type: string               
              enum:
                - {code: _DedicatedServiceDeliveryLocationRoleType,display: DedicatedServiceDeliveryLocationRoleType} 
                - {code: _DedicatedClinicalLocationRoleType,display: DedicatedClinicalLocationRoleType} 
                - {code: DX,display: Diagnostics or therapeutics unit} 
                - {code: CVDX,display: Cardiovascular diagnostics or therapeutics unit} 

Yes, I know you could say this is an implementation issue with the tools, but I would just like to know how to link two or more value sets so that they are consistent rather than having separate enum sets for "code" and "display" strings.

@handrews
Copy link
Member

handrews commented May 6, 2021

@Tasselhoff the answer is still the same as in earlier comments. Since this is fundamentally a JSON Schema concern, there is a JSON Schema issue tracking the codegen: namedEnum approach (although the example there uses docHint: enum - I doubt either of those will be the actual name). It is also possible for a 3rd-party to implement this as a JSON Schema extension vocabulary. See also #2542. Anything about anything "rendering" is definitely a tooling issue and not a spec issue.

@Tasselhoff
Copy link

Tasselhoff commented May 14, 2021

I've made a suggestiion in swagger-ui that integrates both linked fields and parent-child relationships, but it straddles the rendering and the OpenAPI Specification implementation swagger-api/swagger-ui#7260

Edit: as you can no doubt see, I'm pretty new at this and my desire for certain functionality far exceeds my technical domain knowledge...

@webron
Copy link
Member

webron commented Mar 31, 2022

We've decided to close this issue, following @handrews's proposal.

For reference:

codeGen: namedEnum
oneOf:
  - const: 1
    title: Sunny
    description: Blue sky
  - const: 2
    title: Cloudy
    description: Slightly overcast
  - const: 3
    title: Rainy
    description: Take an umbrella with you

The oneOf different const values allows you to define an extended enum structure with any additional information required, ending with an equivalent result.

Regarding the concerns about code-generation - we feel code generators can detect such structure and convert it to enum stucts if needed. As proposed by @handrews, there can be a codegen vocabulary that adds annotations to give hints to such tools (see: codeGen: namedEnum). If anyone is interested in working on such a vocabulary, please join the discussion at https://github.com/json-schema-org/vocab-idl.

Since now we're fully aligned with JSON Schema, any changes to how schemas are defined in OpenAPI would be addressed by the JSON Schema team and not the OpenAPI.

@xiaoxiangmoe
Copy link

@webron I can't find any documentation for the codeGen field in JSON Schema Standard. Could you please provide the corresponding documentation? Thank you a lot.

@handrews
Copy link
Member

@xiaoxiangmoe codeGen was an example proposal. It and other code generation ideas need to be fleshed out.

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

No branches or pull requests