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

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

Open
ahl opened this issue Oct 5, 2023 · 9 comments
Open
Labels
clarification requests to clarify, but not change, part of the spec re-use: globals/defaults Default or global components that can be overridden in some way

Comments

@ahl
Copy link

ahl commented Oct 5, 2023

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
@handrews
Copy link
Member

handrews commented Oct 5, 2023

@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
Copy link
Member

handrews commented Oct 5, 2023

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?)

@ahl
Copy link
Author

ahl commented Oct 6, 2023

  • 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.

@MikeRalphson
Copy link
Member

@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.

@whitlockjc
Copy link
Member

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.

@ahl
Copy link
Author

ahl commented Oct 6, 2023

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.

@karenetheridge
Copy link
Contributor

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.

@ahl
Copy link
Author

ahl commented Jan 20, 2024

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.

@handrews handrews modified the milestones: v3.1.1, v3.0.4 Jan 27, 2024
@handrews handrews added clarification requests to clarify, but not change, part of the spec and removed 3.0 needs documentation labels Jan 27, 2024
@handrews handrews added the re-use: globals/defaults Default or global components that can be overridden in some way label Feb 3, 2024
@handrews
Copy link
Member

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 handrews removed this from the v3.0.4 milestone Apr 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clarification requests to clarify, but not change, part of the spec re-use: globals/defaults Default or global components that can be overridden in some way
Projects
None yet
Development

No branches or pull requests

6 participants
@MikeRalphson @whitlockjc @karenetheridge @ahl @handrews and others