OpenAPI-Specification icon indicating copy to clipboard operation
OpenAPI-Specification copied to clipboard

The Response object's `default` field is confusing and inconsistently interpreted

Open ahl opened this issue 9 months ago • 9 comments

According both 3.0 and 3.1, in theResponse object there MUST be at least one response code and it SHOULD be the response for a successful operation call. In addition the default describes “responses other than the ones declared for specific HTTP response codes”.

This means that if we had a 200 response and default, the latter would cover everything except for 200. Many seem to interpret default to mean something like response categories not covered by explicit response codes. Consider this example from the OAI org:

responses:
        '200':
          description: pet response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

https://github.com/OAI/OpenAPI-Specification/blob/main/examples/v3.0/petstore-expanded.yaml

This implies that default covers error types when in fact it covers non-error responses as well. In fact, the consumer wouldn't necessarily know if the API might reply with another success code such as a 204. A more precise example might look like this:

responses:
        '200':
          description: pet response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'
        4xx:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        5xx:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

I would suggest the following actions:

  1. Update the example to interpret the spec more literally
  2. Clarify default since this confusion is not limited to this example, but extends to APIs in the wild
  3. Consider in 3.2 or 4.0 eliminating default
  4. Consider in 3.2 or 4.0 adding a new named error category that means "both 4xx and 5xx". This could be used in the way that default is often misused today

ahl avatar Oct 05 '23 22:10 ahl

@ahl looking over this to see where it might fit in terms of releases and SemVer, I have a few questions:

  • Why not simply use a 2XX to exclude the other 200-series codes from default? The spec makes it clear that the 200 response would take precedence over 2XX when an actual 200 response is returned.
  • Since Response Objects can be referenced, why not just $ref the same response from both 4XX and 5XX? That is two additional lines of spec, but that's not much in the grand scheme of OAS versbosity.

I agree that regardless, the wording of the examples is misleading, so I will tag this for 3.0.4 and 3.1.1 as those aspects should be fixed in those patch versions, regardless of what might happen in 3.2.

handrews avatar Oct 05 '23 23:10 handrews

I'm also going to tag this as "3.0 needs documentation" because we could explain it on the learn.openapis.org site and I think that's what that label is for (@MikeRalphson @webron is that correct? I guess I could file it over on the OAI/Documentation repo instead?)

handrews avatar Oct 05 '23 23:10 handrews

  • Why not simply use a 2XX to exclude the other 200-series codes from default? The spec makes it clear that the 200 response would take precedence over 2XX when an actual 200 response is returned.

I want to describe an operation that

  1. responds with a 200 upon success and a particular response body
  2. does not respond with any other 2xx responses
  3. responds with a different response body with all 4xx and 5xx responses

In other words, if the API were to erroneously respond with a 204 there would be no guarantee that the response body conformed to the same schema as would, say, a 400 response.

  • Since Response Objects can be referenced, why not just $ref the same response from both 4XX and 5XX? That is two additional lines of spec, but that's not much in the grand scheme of OAS versbosity.

I think that's the accurate way of describing the example. Why don't others just do that? I'd imagine they're being less precise, are confused, or are blithely following examples... from the OAI org.

What would you say an intended or well-formed use of default? How would it be used on its own? How would it be used in concert with other, discrete status codes?

I agree that regardless, the wording of the examples is misleading, so I will tag this for 3.0.4 and 3.1.1 as those aspects should be fixed in those patch versions, regardless of what might happen in 3.2.

Again, consider this example: https://github.com/OAI/OpenAPI-Specification/blob/main/examples/v3.0/petstore-expanded.yaml

Do the operations return a single success code or might there be other ones? If the operation above responded with a 204 would its response body conform to #/components/schemas/Error? Seems unlikely, but the definition of default suggests that's the case.

ahl avatar Oct 06 '23 05:10 ahl

@handrews the documentation label definitely predates the learn.openapis.org site, however it is a good fit to indicate a PR against learn would be appropriate.

MikeRalphson avatar Oct 06 '23 08:10 MikeRalphson

I want to describe an operation that

  1. responds with a 200 upon success and a particular response body
  2. does not respond with any other 2xx responses
  3. responds with a different response body with all 4xx and 5xx responses

In other words, if the API were to erroneously respond with a 204 there would be no guarantee that the response body conformed to the same schema as would, say, a 400 response.

In my opinion, the onus is on you to document the known responses. When you say "if the API were to erroneously respond with a 204 there would be no guarantee that the response body conformed to the same schema as would, say, a 400 response", that's not an OpenAPI problem. If your API can return a 204, you should document it as such unless it happens to have the same structure as default...if you provide it. default is only useful when you have a collection of status codes that have the same response structure, which in many/most cases error responses would apply. So to me, OpenAPI can't be expected to handle "erroneous [responses]" as that is a failure on the API to adhere to the contract.

whitlockjc avatar Oct 06 '23 14:10 whitlockjc

In my opinion, the onus is on you to document the known responses.

On the API description author... sure! I would merely observe that mistakes have occurred in the past, and are likely to occur in the future.

So to me, OpenAPI can't be expected to handle "erroneous [responses]" as that is a failure on the API to adhere to the contract.

Perhaps the hypothetical was confusing. How about this:

Consider https://github.com/OAI/OpenAPI-Specification/blob/main/examples/v3.0/petstore-expanded.yaml What response codes does, say, the addPets operation respond with? One could infer that 200 is the only success response, but what in the OpenAPI spec tells us that this is so? If default actually, de facto, is meant to describe "responses in http status code categories not covered by explicit or ranged response descriptions", then perhaps the spec should say that.

ahl avatar Oct 06 '23 16:10 ahl

One could infer that 200 is the only success response, but what in the OpenAPI spec tells us that this is so? If default actually, de facto, is meant to describe "responses in http status code categories not covered by explicit or ranged response descriptions", then perhaps the spec should say that.

It does say that. It says, for the default keyword:

The documentation of responses other than the ones declared for specific HTTP response codes.

So if you only document 200 and default, your document is specifically saying that anything but 200 must conform to the schema specified for default. If that references an Error schema, then you may conclude that there are no other 2xx (non-error) responses to be returned, and if the application does so it may be considered a violation of the schema.

karenetheridge avatar Oct 08 '23 19:10 karenetheridge

One could infer that 200 is the only success response, but what in the OpenAPI spec tells us that this is so? If default actually, de facto, is meant to describe "responses in http status code categories not covered by explicit or ranged response descriptions", then perhaps the spec should say that.

It does say that. It says, for the default keyword:

The documentation of responses other than the ones declared for specific HTTP response codes.

The additional detail I suggested was intentionally to distinguish it from the existing definition of "default". In particular the language "in categories not covered by explicit or ranged responses". This may be another case where more words would be clearer than fewer. My suggestion is that default would apply to status code ranges that are otherwise not mentioned. For example, if there is an entry for a 200, then default would not apply to the 2xx range. If there was a 404, default would similarly not apply to the 400 range.

Put perhaps another way. A common use of default is to cover the 4xx and 5xx range with an error response type. I think there would be utility in a spec being able to say "this is what a 200 response looks like and there will be no other 2xx responses".

Or perhaps "default" is insufficiently specific, and an "error" response that covers the 4xx and 5xx range would be more useful and intelligible.

ahl avatar Jan 20 '24 06:01 ahl

if there is an entry for a 200, then default would not apply to the 2xx range. If there was a 404, default would similarly not apply to the 400 range.

This would be a breaking change, so it couldn't be done until OAS 4 "Moonwalk" where things are being re-imagined on a larger scale, including API-level responses. You might want to follow those discussions to see if there's an analogous concern with the new format.

On the one hand, I kind of like the error idea, but since it's already possible to $ref Response Objects, you can accomplish it by just $ref-ing the same response from 4XX and 5XX. It doesn't seem worth adding more work for implementations just to save one reference.

handrews avatar Apr 20 '24 01:04 handrews