Closed halmai closed 4 years ago
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?
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.
@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.
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.
@fcanela you do have a to model a constant value. What @halmai suggested was syntactic sugar.
@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.
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
@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).
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.
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.
@andy-maier specifically what you're describing is more of a tooling issue than a spec issue.
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.
@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!)
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.
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):
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.
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.
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 https://github.com/swagger-api/swagger-codegen/issues/7756#issuecomment-370137779
@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.
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.
@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.
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.
This was fixed in #1977 so we can close this.
@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.
Did anyone ever use const
in a response in OAI 3.1? How does it work? Is there any documentation available? :pray:
@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.
Thank you so much for taking the time to post that example - this is awesome! :rocket:
Let's see if this is also supported by our tooling :upside_down_face:
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
The best way I found for describing this is to use enums with only one element, like this:
Instead of this, an exact value should be defined with an implicit type detection. So,
should mean the same as the previous declaration. The following scalar types should be auto-detected:
Moreover, the new
value
declaration should work one level above as well:This specification should mean a structure that has the two fields with these two constant values.
One more step would be the following notation:
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.