OAI / OpenAPI-Specification

The OpenAPI Specification Repository
https://openapis.org
Apache License 2.0
29k stars 9.07k forks source link

Do we need to clarify what a response missing content means #3536

Open philsturgeon opened 9 months ago

philsturgeon commented 9 months ago

I've been writing up guides for contract testing with OpenAPI in a bunch of different languages, and the Ruby on Rails one using https://github.com/mkon/openapi_contracts/ gave this great example, letting me know an empty response has been defined, but a response has been provided by the API implementation.

1) widgets POST /widgets responds with 201 when valid
    Failure/Error: expect(response).to match_openapi_doc(OPENAPI_DOC)
      * Expected empty response body
    # ./spec/requests/widgets_spec.rb:17:in `block (3 levels) in <top (required)>'

Here's some OpenAPI for visual people:

post:
  summary: Create Widget
  operationId: create-widget
  requestBody:
    description: Widget to create
    required: true
    content:
      application/json:
        schema:
          $ref: "../components/schema/widget.yaml"
  responses:
    '201':
      description: Created

Does this mean "There is definitely no content" or "I haven't bothered defining it but dont worry about it"?

There are ways to define a "dont worry about it" thats a bit more specific, like:

post:
  summary: Create Widget
  operationId: create-widget
  requestBody:
    description: Widget to create
    required: true
    content:
      application/json:
        schema:
          $ref: "../components/schema/widget.yaml"
  responses:
    '201':
      description: Created
      content:
        application/json:
          schema:
            type: object

Or you can pop an example in instead of worrying about defining a schema but still providing something tangible for docs/mocks to think about.

Scrabbling round the spec I coudn't find anything in 3.0 or 3.1 but the SmartBear Guide on Describing Responses does explicitly say:

Some responses, such as 204 No Content, have no body. To indicate the response body is empty, do not specify a content for the response:

This leads me to think all responses missing a content should have no body, because otherwise there's going to be some weird logic going "If 204 then missing means definitely no body but otherwise it just means I dunno!"

Would that be a breaking change to 3.1.x if its clarifying intent? Or does this have to go to Moonwalk?

handrews commented 9 months ago

Thanks, @philsturgeon ! See also:

iglosiggio commented 3 months ago

Hi! I need the same clarification:

Does this mean "There is definitely no content" or "I haven't bothered defining it but don't worry about it"?

I'm working on some scaffolding tools that have to extract meaning from these kinds of situations. My original interpretation was "will have a response with something" but that obviously breaks the intention when 204 - No Content is meant.

So:

I saw the discussion at #2236 but that's outside my current scope because we are not intending to support optionally present responses (yet).

karenetheridge commented 3 months ago

How can we specify "There's no content on this response"?

It depends on what you mean...

lornajane commented 3 months ago

Discussion in TDC this week, we don't think we can infer from an absence of response information in an API description whether this means there is no response expected, or the response information is missing from the API description file.

karenetheridge commented 3 months ago

How can we specift "This response may have anything as its contents"?

I would do that with...

responses:
  2xx:
    content:
      */*:
        schema: {}

..but responses isn't a required part of an openapi specification, so you can just omit it entirely if you like. You would only need to do the above if you want to be more specific for error responses (e.g. 4xx) and leave the 2xx response as more lax.

karenetheridge commented 3 months ago

Given the questions in this thread, we might need to be more explicit in the specification that absence of a specification does NOT indicate that a particular component must be absent; rather the lack of a specification for a thing means that anything is allowed. I'm sure there is some kind of strict language in RFC-style that can be used here, rather than doing it colloquially.

iglosiggio commented 3 months ago

Thanks for the detailed response!

  • Do you mean "There must not be a Content-Type response header"? If so, you can specify that, by defining a header with a false schema.
  • Do you mean "There must not be a Content-Length response header"? If so, see above.

So something like:

responses:
  200:
    description: "Everything went OK!"
    content:
      */*:
        schema: false

Right?

Is an exception like "A 204 response without schema can be interpreted as a false schema" viable? I know this is ugly, but I saw multiple APIs do:

responses:
  204:
    description: "Don't expect any content from me lol. I'm a 204"
  • Do you mean "Okay, there could be a Content-Length header, but if it exists, it must be zero"? If so, you can specify that too, with "required": false and "schema": "const": "0".

You mean that as a schema for the Content-Length header, right?

Given the questions in this thread, we might need to be more explicit in the specification that absence of a specification does NOT indicate that a particular component must be absent; rather the lack of a specification for a thing means that anything is allowed. I'm sure there is some kind of strict language in RFC-style that can be used here, rather than doing it colloquially.

Maybe something like:

4.8.17.1 Fixed Fields

Field Name Type Description
content Map[string, Media Type Object] A map containing descriptions of potential response payloads. The key is a media type or media type range and the value describes it. For responses that match multiple keys, only the most specific key is applicable. e.g. text/plain overrides text/*. For responses that match no key a Media Type Object with a true schema SHOULD be applied.

If we want a 204 exception:

4.8.17.1 Fixed Fields

Field Name Type Description
content Map[string, Media Type Object] A map containing descriptions of potential response payloads. The key is a media type or media type range and the value describes it. For responses that match multiple keys, only the most specific key is applicable. e.g. text/plain overrides text/*. For responses that match no key a default Media Type Object SHOULD be applied, its schema depends on the status code of the response: false for 204 and true for any other.

The biggest issue with the exception is that it breaks reusability of responses via de $ref mechanism (because now the interpretation of a Response Object depends on the Operation Object that embeds it. Alternatively we can use that the exception is a MAY thing where implementations are allowed but not required to interpret 204 responses in a more strict fashion.