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

Defining constant value in response #1313

Closed
halmai opened this issue Aug 5, 2017 · 26 comments
Closed

Defining constant value in response #1313

halmai opened this issue Aug 5, 2017 · 26 comments

Comments

@halmai
Copy link

halmai commented Aug 5, 2017

In order to specify that the response for an API call is always a certain given value, I would like to create this this feature request.

If the client wants to get the details of a non-existing pet of a pet store then the server should say

{
    "status": "ERROR",
    "error_message": "ERROR__PET_NOT_FOUND"
}

The best way I found for describing this is to use enums with only one element, like this:

    schema:
        type: object
        properties:
            result: 
                type: string
                enum: [ERROR]
            error_code: 
                type: string
                enum: [ERROR__PET_NOT_FOUND]

Instead of this, an exact value should be defined with an implicit type detection. So,

    schema:
        type: object
        properties:
            result: 
                value: "ERROR"
            error_code: 
                value: "ERROR__PET_NOT_FOUND"

should mean the same as the previous declaration.
The following scalar types should be auto-detected:

  • type = string, if the value is surrounded by " symbols
  • type = integer, if the value contains only digits and sign
  • type = float, if the value contains digits, sign AND decimal point

Moreover, the new value declaration should work one level above as well:

    schema:
        type: object
        properties:
            value: 
                result: "ERROR"
                error_code: "ERROR__PET_NOT_FOUND"

This specification should mean a structure that has the two fields with these two constant values.

One more step would be the following notation:

    schema:
        value: 
            result: "ERROR"
            error_code: "ERROR__PET_NOT_FOUND"

This would determine the type to be an objects and the properties as above.

This notation would be much more dense and easier to both write and understand.

@darrelmiller
Copy link
Member

If an API had an exact response then it would seem rather redundant to call it. Why even have an API if it returns the same value every time?

@halmai
Copy link
Author

halmai commented Aug 6, 2017

The above example shows a response which is returned only if the targeted element doesn't exist, that is, with http status code = 404. In other cases it replies something different. The different kinds of errors can produce different responses.

In the project I am working in, the JSON response always has a key "status" which can be either "OK" or "ERROR" and in case of "ERROR" there must exist an "error_code" key as well (and potentially others).

The fact that the response contains the error code as well, it makes the client development easier because the client doesn't have to interpret all the http status codes.

In case of 404 of a particular API endpoint the value of the error_code is always the same but in case of 200 it is varying.

@darrelmiller
Copy link
Member

@halmai Taking my OAI hat off for the moment, because this is purely a personal opinion. Also, this comment isn't directed specifically at you, it is just that your assertion reflects a common belief that I feel needs to be addressed.

You said,

it makes the client development easier because the client doesn't have to interpret all the http status codes

I believe that this is incorrect. Moving the error description into the response body "for consistency" does help map HTTP APIs to a client side RPC signature. It allows HTTP APIs to be presented in a way that client developers are more familiar with. However, it is definitely not easier than using the HTTP status codes as they were intended to be used.

In your example, you already know that the response is a 404. Having a client understand that HTTP Status code 404 means "not found" is not only simple, it is consistent across all HTTP API implementations. Requiring a client developer to have to read a payload of some media type, that has some custom error payload structure, that then has some custom enum that repeats the error "not found" is not easier.

Client libraries do not have to interpret ALL of the HTTP status codes. It needs to understand 200, 300, 400, and 500 plus optionally any extra codes that the client wants to do special handling for. The HTTP spec says that if you receive a status code that you don't understand, round it down to the nearest hundred and treat it as that.

It can be useful to have payloads for response bodies that have additional details. However, there is a standard for that https://tools.ietf.org/html/rfc7807 which has existing implementations. These things should not be reinvented over and over again.

Finally, your original request was the ability to define a schema for a constant value. OpenAPI bases it's schema on JSON Schema, and JSON schema doesn't support what you are trying to do. If you want JSON Schema to change, then I would suggest talking to them, we don't have that authority.

@fcanela
Copy link

fcanela commented Sep 19, 2017

That practice is very common. I am facing the same problem than the original user. Being able to model that constant property would enable us to property document an existing API and feed the API Manager with it accordingly.

@webron
Copy link
Member

webron commented Sep 19, 2017

@fcanela you do have a to model a constant value. What @halmai suggested was syntactic sugar.

@andig
Copy link

andig commented Sep 21, 2017

@darrelmiller I think I have a similar use case. My API returns its version number in the payload which is currently fixed ("0.4"). As the application is distributed as bundle it does not make much sense to version that API by path.

@tobymurray
Copy link

tobymurray commented Oct 11, 2017

OpenAPI bases it's schema on JSON Schema, and JSON schema doesn't support what you are trying to do. If you want JSON Schema to change, then I would suggest talking to them, we don't have that authority.

I've just started using OpenAPI, so I may be lacking a lot of context, but is this json-schema-org ticket an indication that the work on the JSON Schema side has already been done? I.e. the released Pre-preview 2017-03-09 already contains this value, which is visible in the source here.

So is this functionality now blocked by an official release or something of JSON Schema? Is it something OpenAPI can adopt while still in draft?

Specifically:

6.24. const

The value of this keyword MAY be of any type, including null.

An instance validates successfully against this keyword if its value is equal to the value of the keyword

@handrews
Copy link
Member

@darrelmiller @tobymurray @halmai JSON Schema introduced const in draft-06 (technically draft-wright-json-schema-validation-01). I believe OpenAPI 3.0 references draft-wright-json-schema-validation-00. We are about to release another draft (draft-07, exact IETF naming TBD) within the next month or two.

The implementation delta between draft-06 and draft-07 is smaller than that from older drafts to draft-06. And some of it (e.g. moving readOnly from hyper-schema into validation, supporting additional common format values) just reflects what many people already do anyway.

So at this point it depends on if/when OpenAPI chooses to move to a newer draft. There are now draft-06 implementations in the wild in JavaScript, Java, Go, and .NET (and hopefully soon Python).

@darrelmiller
Copy link
Member

We will review updating our support for newer versions of JSON Schema when we are considering the features that will be going into 3.1.

@andy-maier
Copy link

andy-maier commented Nov 16, 2017

I'd like to register my interest in what @halmai originally requested. My use case is that in our responses there are some generic properties for making the response a bit more self-describing. For example, every response has a "kind" property that allows identifying what kind of stuff it contains.

We currently follow what @halmai found, namely to define an enum with one value. For example, the definition of an error response states that "kind" must be "error" as follows:

components:
  responses:
    error:
      content:
        application/json:
          schema:
            properties:
              kind:
                type: string
                enum: [error]
              ... (more properties) ...

In the Swagger 3.x editor, the Model view of the response shows that property as:

Enum:
   > Array [ 1 ]

When opening the > twistie, the enumeration shows its one value:

Enum:
   v [ error ]

That is quite inconvenient, and a const definition for such a fixed value would allow the editor to show the value right away.

Plus, stating a required fixed value via a construct such as "const" is semantically really much more to the point of what the interface wants to express in such a case., compared to defining an enum with one value.

I'm looking forward to see OpenAPI 3.1 embrace this feature from the JSON schema.

@webron
Copy link
Member

webron commented Nov 16, 2017

@andy-maier specifically what you're describing is more of a tooling issue than a spec issue.

@andy-maier
Copy link

I have meanwhile found the same behavior also in the Python client generated by the Swagger 2.0 tooling, and have come to the conclusion that the tooling has no chance (!!) to convert an enum with one value into a const.

The reason for that is that it is possible that the enum list becomes longer in a future version of the API YAML file, so the tooling has to present that faithfully as specified, in order not to cause an incompatible change for its users in the future (e.g. a Python program using the API provided by the generated Python client module).

As long as the API YAML file does not distinguish between an enum with one value (that might become more than one value in the future) and a fixed value, the tooling must behave that way.

So the spec format is the root cause for the behavior of the tooling, and that is not just a flaw in the tooling.

@handrews
Copy link
Member

@andy-maier that's a really interesting point that I didn't even think of when we added const to JSON Schema! (btw, draft-07 is out!)

@phal0r
Copy link

phal0r commented Feb 2, 2018

I agree with @andy-maier: We have the same use case with the difference, that we call it type not kind for each entity ;)

We took the same approach with using enum with one element. During the time, there were misinterpretations, where developer would mistakenly assume, that this property is an array, while using the swagger ui.

@jmini
Copy link

jmini commented Feb 7, 2018

We are interested by OpenAPI supporting the notion of a constant in the schema definition.

For legacy reasons on the backend, the current API I am working on requires in each object a constant to be defined. Its more of less represent the precise type of the object and helps the server to perform the deserialisation correctly.

This means that each JSON Object sent by the client needs to set the information, which is the same for all objects corresponding to a specific schema. Example:

{
  "$_type": "User",
  "id": 132,
  "firstName": “John”,
  "lastName": “Doe”
}

Right now we are using the enum approach described in this issue:

components:
  schemas:
    User:
      type: object
      properties:
        $_type:
          type: string
          enum:
            - User
        id:
          type: integer
        firstName:
          type: string
        lastName:
          type: string

It looks well in the documentation (swagger online editor):

Documentation screenshot

In the client (java code in this example), need explicitly to set the type each time an object is instantiated:

User u = new User();
u.setType(TypeEnum.USER);
u.setId(132);
u.setFirstName("John");
u.setLastName("Doe");

With a constant, I assume that the line u.setType(..) would not be necessary to generate the same JSON Payload.

@jmini
Copy link

jmini commented Feb 20, 2018

Having a constant could be interesting for the Inheritance and Polymorphism case (when a discriminator and a mapping are defined in a oneOf schema). Take this example from the guide:

components:
  responses:
    sampleObjectResponse:
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/Object1'
              - $ref: '#/components/schemas/Object2'
            discriminator:
              propertyName: objectType
              mapping:
                obj1: '#/components/schemas/Object1'
		obj2: '#/components/schemas/Object2'
  …
  schemas:
    Object1:
      type: object
      required:
        - objectType
      properties:
        objectType:
          type: string
      …
    Object2:
      type: object
      required:
        - objectType
      properties:
        objectType:
          type: string
      …

In this case, objectType defined in #/components/schemas/Object1 and in #/components/schemas/Object2 is just present for the discriminator mapping, it would be much nicer to have it defined as constant.

@jnovotny
Copy link

jnovotny commented Mar 3, 2018

I'd love to see this implemented as I'm having difficulty with geojson_swagger

For Point: http://geojson.org/geojson-spec.html#id2
For Polygon: http://geojson.org/geojson-spec.html#id4

Please see my original issue at swagger-api/swagger-codegen#7756 (comment)

@handrews
Copy link
Member

@jmini on the JSON Schema side, we're hoping to add a code generation vocabulary with the OpenAPI community being one of the main drivers. This would provide a standardized way to disambiguate JSON Schema validation constructs that were never intended to be used without an instance. e.g. an allOf might be used for inheritance or composition, but there's no clear way to indicate that.

I'm rather hoping that discriminator won't be needed after that (it breaks some assumptions in JSON Schema or else we'd try to adopt it in the vocabulary).

We definitely have found in draft-06 schemas that const makes many oneOf use cases much more clear. In draft-07, const + if makes certain cases even more clear, although not always concise.

@gvdmarck
Copy link

Is there any update on this ? If you want a clear use-case, just think json:api :

GET /articles/

response:

{
  "data": [
    {
    "type": "articles",
    "id": "1",
    ...
   },
   {
    "type": "articles",
    "id": "2",
    ...
   },
   {
    "type": "articles",
    "id": "3",
    ...
   }, ...]
}

The current workaround (enum with one value) is so hacky I don't understand how it is sufficient/reasonable for everyone.

@handrews
Copy link
Member

@gvdmarck JSON Schema 2019-09 (formerly known as draft-08) has now been published.

PR #1977 in this repository updates OpenAPI's Schema Object for OAS 3.1 to use JSON Schema 2019-09, which includes the const keyword (added back in draft-06). Assuming that PR is eventually accepted, it will solve this problem in OAS 3.1.

@ffMathy
Copy link

ffMathy commented Dec 20, 2019

Any progress on this? I'm personally interested in it from the polymorphism perspective @jmini pointed out.

It's very powerful in TypeScript, since that supports constant string values, and can use it as descriminators.

@philsturgeon
Copy link
Contributor

This was fixed in #1977 so we can close this.

LucasRoesler added a commit to contiamo/go-base that referenced this issue Jul 20, 2020
**What**
- Generate a Go `const` if the enum values has exactly one element
- See OAI/OpenAPI-Specification#1313 and
  OAI/OpenAPI-Specification#1620 as examples
  where the openapi team blessed the "singleton enum" example

Signed-off-by: Lucas Roesler <roesler.lucas@gmail.com>
rdner pushed a commit to contiamo/go-base that referenced this issue Jul 20, 2020
**What**
- Generate a Go `const` if the enum values has exactly one element
- See OAI/OpenAPI-Specification#1313 and
  OAI/OpenAPI-Specification#1620 as examples
  where the openapi team blessed the "singleton enum" example

Signed-off-by: Lucas Roesler <roesler.lucas@gmail.com>
@seyedmmousavi
Copy link

@halmai Taking my OAI hat off for the moment, because this is purely a personal opinion. Also, this comment isn't directed specifically at you, it is just that your assertion reflects a common belief that I feel needs to be addressed.

You said,

it makes the client development easier because the client doesn't have to interpret all the http status codes

I believe that this is incorrect. Moving the error description into the response body "for consistency" does help map HTTP APIs to a client side RPC signature. It allows HTTP APIs to be presented in a way that client developers are more familiar with. However, it is definitely not easier than using the HTTP status codes as they were intended to be used.

In your example, you already know that the response is a 404. Having a client understand that HTTP Status code 404 means "not found" is not only simple, it is consistent across all HTTP API implementations. Requiring a client developer to have to read a payload of some media type, that has some custom error payload structure, that then has some custom enum that repeats the error "not found" is not easier.

Client libraries do not have to interpret ALL of the HTTP status codes. It needs to understand 200, 300, 400, and 500 plus optionally any extra codes that the client wants to do special handling for. The HTTP spec says that if you receive a status code that you don't understand, round it down to the nearest hundred and treat it as that.

It can be useful to have payloads for response bodies that have additional details. However, there is a standard for that https://tools.ietf.org/html/rfc7807 which has existing implementations. These things should not be reinvented over and over again.

Finally, your original request was the ability to define a schema for a constant value. OpenAPI bases it's schema on JSON Schema, and JSON schema doesn't support what you are trying to do. If you want JSON Schema to change, then I would suggest talking to them, we don't have that authority.

But this approach doesn't seem to be right. Just take a look at https://softwareengineering.stackexchange.com/a/305294/244734
Getting tied to the underlying technology doesn't seem like a good idea.

@uniqueg
Copy link

uniqueg commented Jun 21, 2024

Did anyone ever use const in a response in OAI 3.1? How does it work? Is there any documentation available? 🙏

@handrews
Copy link
Member

@uniqueg const is a standard JSON Schema keyword so you can see its documentation in JSON Schema draft 2020-12 (which is linked from the OAS 3.1 specification).

It works just like two of the proposed solutions in the original comment, but with const in place of value:

You can use it for individual properties:

    schema:
        type: object
        properties:
            result: 
                const: "ERROR"
            error_code: 
                const: "ERROR__PET_NOT_FOUND"

Or as the entire schema:

    schema:
        const: 
            result: "ERROR"
            error_code: "ERROR__PET_NOT_FOUND"

There was another syntax proposed in the initial comment that put value directly under properties - that is not supported because keywords can only appear in schema objects, and the immediate value of properties is an object of schemas, not a schema itself.

@uniqueg
Copy link

uniqueg commented Jun 21, 2024

Thank you so much for taking the time to post that example - this is awesome! 🚀

Let's see if this is also supported by our tooling 🙃

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