OAI / OpenAPI-Specification

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

Proposal: Default responses for all endpoints #521

Closed sebastiandemel closed 8 months ago

sebastiandemel commented 8 years ago

I suggest that we add "default responses" that can be defined as default response for All endpoints. This would avoid copy-paste for some common responses like:

429 Too Many Requests 405 Method Not Allowed

The format could be

produces:
  - application/json
responses:
  '429':
    description: to many requests in the given timeframe
    schema:
      $ref: '#/definitions/error'
paths:
...

Or if flexibility is required, we could alter the default response keyword to take a list of responsedefinitions. This could benefit with the response code range proposal (https://github.com/swagger-api/swagger-spec/issues/516).

responseDefinitions:
 "success":
    description: request successful
    code: 200
  "request limit":
    description: to many requests in the given timeframe
    code: 429, 419
    schema:
      $ref: '#/definitions/error'
  "server error":
    description: server error
    code: 500 - 599
    schema:
      $ref: '#/definitions/error'

paths
  test:
    get:
      responses:
        default:
         - "success"
         - "request limit"
         - "server error"

this would require some changes to the default response keyword.

mrname commented 8 years ago

:+1: to the suggestion. As you mentioned, this would save A LOT of copy/paste.

jharmn commented 8 years ago

Link to meta #566

MikeRalphson commented 6 years ago

Just a reminder, please use github reactions, rather than "+1" comments (two recent ones deleted).

marmax commented 5 years ago

Is there any progress with this? The ticket is open for more than 3 years now... :(

NoiseByNorthwest commented 5 years ago

I cannot imagine why this is not fixed yet as this issue just makes impossible to specify an error for an invalid path (404) or method (405).

nogates commented 5 years ago

you can reference responses, which is more or less what is being requested here:

paths:
  /my_endpoint:
    get:
      responses:
        404:
          $ref: "#/components/responses/notFound"
        405:
          $ref: "#/components/responses/methodNotAllowed"
  /other:
    get:
      responses:
        404:
          $ref: "#/components/responses/notFound"
        405:
          $ref: "#/components/responses/methodNotAllowed"
components:
  responses:
    notFound:
      description: "Not found response"
      content":
        application/json":
          schema:
            $ref: "#/components/schemas/notFoundResponse"
    methodNotAllowed:
      description: "Method Not Allowed response"
      content":
        application/json":
          schema:
            $ref: "#/components/schemas/methodNotAllowedResponse"

I know this is much more verbose, but at least is a workaround....

saturov commented 4 years ago

+1 dream about this feature

avsmirnov567 commented 4 years ago

+1, will be useful

artem-zaitsev commented 4 years ago

+1, amazing feature

ozh-dev commented 4 years ago

+1, I will be gratefull

alexcambose commented 4 years ago

+1 this will save a lot of repeating docs code

Metroxe commented 4 years ago

+1 would save a lot of time

matthiassb commented 4 years ago

+1

malotho-zz commented 4 years ago

this will be usefull

erdimeola commented 4 years ago

This would be incredibly useful and performance booster!

baguse commented 4 years ago

its so helpfull if this feature is exist

Havunen commented 4 years ago

We have about 800 endpoints. Repeating the same error response references everywhere increases the JSON a lot...

Blacklands commented 4 years ago

I'm also wondering how this isn't a thing yet. There's so many responses that are just part of every single endpoint by default. Things like "content-type not supported", "invalid credentials", "request entity too large", "malformed content", and more... Are we not supposed to add these to the API at all? Or are we really supposed to add these manually to every endpoint?

Also, what about responses that aren't even tied to an endpoint at all? For example, an "endpoint does not exist" response? I obviously can't add that response to any of the endpoint definitions.

Maybe some of those are not supposed to be part of the API definition at all, but I'm using RFC 7807 for my error responses and I want to give a unique response for each error so that clients can switch on the type for error handling. Currently this is a big pain to do.

MikeRalphson commented 4 years ago

I'm currently looking at the possible need to add a default / override for the JSON Schema, $schema $vocabulary etc keywords in OAS 3.1

A design question comes up between simplicity and extensibility of this "default" feature.

Would something like:

openapi: 3.1.0
info:
  title: API
  version: 1.0.0
defaults:
  responses:
    '405':
     description: Method not allowed
     schema:
       $ref: '#/components/responses/error'
    '429':
      description: Too many requests
      schema:
        $ref: '#/components/responses/error'
      headers:
       ....

address the requirements for people in this issue? Bearing in mind @darrelmiller's very good advice in this tweet.

devdilson commented 3 years ago

+1 for this feature!

mxmlnglt commented 3 years ago

I'm interested in that. Similar to what's been discussed so far in https://github.com/OAI/OpenAPI-Specification/issues/563

omgkotofey commented 3 years ago

+1

bodograumann commented 3 years ago

@MikeRalphson With regards to the tweet: Does the spec already contain some language whether the defined responses should be exhaustive? When manually implementing an API client this information might be gathered from description texts or sources outside the openapi definition, but for code generation it is unclear, I think.

It would be really interesting to know whether people actually need to define common responses for all endpoints, or just some sensible fall-back handling for all kinds of undefined responses. If you like respond with :tada: for default handling would be enough and with :rocket: if having explicit definition for common responses would give you more.

darrelmiller commented 3 years ago

I have an in-progress update to the Overlay specification to suggest enabling this method to apply defaults to an OpenAPI description using an Overlay.

#### Default Overlays Examples

Using wildcards and the `default` action, overlays can be used to provide default behavior.

```yaml
overlay: 1.0.0
info:
  title: Provide defaults where objects don't exist
  version: 1.0.0
updates:
- target: paths.*.get.responses.400
  default:
    description: Bad request
    content:
      application/http-problem:
        schema:
          $ref: "/components/schemas/badRequestProblem"

- target: paths.*.get.responses.404
  default:
    description: Not found
    content:
      application/http-problem:
        schema:
          $ref: "/components/schemas/notFoundProblem"
- target: paths.*.get.responses.5XX
  default:
    description: Server Error
    content:
      application/http-problem:
        schema:
          $ref: "/components/schemas/serverErrorProblem"
karenetheridge commented 3 years ago

Would there be any way of indicating some default responses as a combination of status code + headers + body? For example 301 + Location, 400 + Content-Type: application/problem+json, 503 + Retry-After.

piotr-yuxuan commented 2 years ago

Common responses with http status codes, schemas, and example, or at least common errors, would be really great to have and would allow to focus endpoint description only on specific success responses and specific, meaningful error responses.

ginosian commented 2 years ago

This is a must-have feature, and it's disappointing that the issue was opened back in 2015, and no lead still. Upvote!

NoiseByNorthwest commented 2 years ago

you can reference responses, which is more or less what is being requested here:

paths:
  /my_endpoint:
    get:
      responses:
        404:
          $ref: "#/components/responses/notFound"
        405:
          $ref: "#/components/responses/methodNotAllowed"
  /other:
    get:
      responses:
        404:
          $ref: "#/components/responses/notFound"
        405:
          $ref: "#/components/responses/methodNotAllowed"
components:
  responses:
    notFound:
      description: "Not found response"
      content":
        application/json":
          schema:
            $ref: "#/components/schemas/notFoundResponse"
    methodNotAllowed:
      description: "Method Not Allowed response"
      content":
        application/json":
          schema:
            $ref: "#/components/schemas/methodNotAllowedResponse"

I know this is much more verbose, but at least is a workaround....

This is an absolute nonsense, how a declared "GET /my_endpoint" could result in a 404 or 405, these errors only apply to the inverse set of declared endpoints, which is the infinite set of undeclared things.

iekdosha commented 2 years ago

Adding a global response might make the contract definition much more "implicit" and I get that. On the other hand this feature can be handy for many specific use cases.

For example: I an developing a platform that generates server API from openAPI contract for developer which in turn will implement the contract. The web server I use performs some validations on incoming requests (vertx-web-openapi is the web server). It would be nice if I can auto add that response to all new endpoints, something some developers using this platform will almost certainly won't, because this error itself is "implicit" in the code.

I am not sure if it is a good/bad idea to have this feature but there might be a solution in between.

ronaldwanink commented 2 years ago

+1 Surprised this is not implemented yet, this would save me lots of work

Malagutte commented 2 years ago

Any updates about this?

sarangsbabu367 commented 2 years ago

you can reference responses, which is more or less what is being requested here:

paths:
  /my_endpoint:
    get:
      responses:
        404:
          $ref: "#/components/responses/notFound"
        405:
          $ref: "#/components/responses/methodNotAllowed"
  /other:
    get:
      responses:
        404:
          $ref: "#/components/responses/notFound"
        405:
          $ref: "#/components/responses/methodNotAllowed"
components:
  responses:
    notFound:
      description: "Not found response"
      content":
        application/json":
          schema:
            $ref: "#/components/schemas/notFoundResponse"
    methodNotAllowed:
      description: "Method Not Allowed response"
      content":
        application/json":
          schema:
            $ref: "#/components/schemas/methodNotAllowedResponse"

I know this is much more verbose, but at least is a workaround....

Its a workaround. But its still much the same(Copying and pasting). And in this case, adding one more error to all paths will be a headache.

NoiseByNorthwest commented 2 years ago

This is an absolute nonsense, how a declared "GET /my_endpoint" could result in a 404 or 405, these errors only apply to the inverse set of declared endpoints, which is the infinite set of undeclared things.

I got 4 downvotes just because I said that if GET /my_endpoint is a defined endpoint then it cannot result in a 404 or 405 which is... factual.

darrelmiller commented 2 years ago

There is a proposal for enabling this via Overlays. https://github.com/OAI/Overlay-Specification/pull/17/files#diff-2df9558a570116ce439ac7523cbed07a4a3a1b14d29a21f01920eb09f33df370R198

mxmlnglt commented 2 years ago

This is an absolute nonsense, how a declared "GET /my_endpoint" could result in a 404 or 405, these errors only apply to the inverse set of declared endpoints, which is the infinite set of undeclared things.

I got 4 downvotes just because I said that if GET /my_endpoint is a defined endpoint then it cannot result in a 404 or 405 which is... factual.

How a GET could NOT result in a 404... please explain that... 🤔

NoiseByNorthwest commented 2 years ago

How a GET could NOT result in a 404... please explain that... thinking

I cannot, because it could, I was indeed wrong about 404 (I was confusing resource / endpoint).

However there is still the 405 case.

sarangsbabu367 commented 2 years ago

How a GET could NOT result in a 404... please explain that... thinking

I cannot, because it could, I was indeed wrong about 404 (I was confusing resource / endpoint).

However there is still the 405 case.

405 stands for method-not-allowed. So why this status is not allowed for GET /my_endpoint?

NoiseByNorthwest commented 2 years ago

405 stands for method-not-allowed. So why this status is not allowed for GET /my_endpoint?

It is allowed, but why would you define GET /my_endpoint if in the end it returns a 405 (GET not allowed) ?

Jackman3005 commented 2 years ago

People are always free to return whatever status code they'd like, so even if it wouldn't make sense, if they did it, should OpenAPI support documenting it or should it be disallowed?

I feel like the whole point of OpenAPI is to have a way of documenting the behavior of endpoints, even if it doesn't make sense.

I think it's a bit interesting what you mentioned about documenting "the infinite set of undeclared things". It's possible that could be useful as well...

I was assuming that "Default responses for all endpoints" would only apply to endpoints that have been declared, but maybe there is something useful in being able to declare defaults(?) for undeclared endpoints as well. Might not be worth the hassle until someone with that use-case chimes in, though.

NoiseByNorthwest commented 2 years ago

I was assuming that "Default responses for all endpoints" would only apply to endpoints that have been declared, but maybe there is something useful in being able to declare defaults(?) for undeclared endpoints as well. Might not be worth the hassle until someone with that use-case chimes in, though.

"Default response" could also mean "Default response for anything, declared or not, under / (i.e. matching /*)".

And we could even go further with the possibility to declare defaults for a path pattern (i.e. other than the default /*).

As previously mentionned, Overlay spec https://github.com/OAI/Overlay-Specification seems to not address this use case. AFAIU it allows to generate a new OAS spec with all "defaults" expanded to the targeted endpoints.

webron commented 2 years ago

We're not really in the business of defining what's... not defined. Same way you don't have to define all response codes for any given operation (it's pointless in many cases). There's no benefit of defining what might come back from an unknown endpoint in case someone happens to hit it. If you want people to know what might be returned from such an endpoint, just define the endpoint.

unional commented 2 years ago

IMO I also think that this is not a responsibility of OpenAPI. It can be achieved by creating another package and distribute that for reuse.

However, the problem is about the reuse.

Currently, we cannot use allOf to combine responses. And since the response body is application specific, any predefined responses cannot be reused.

For example, assume you have this shared spec:

# shared.yml
components:
  responses:
    201.Created:
      description: Created
      headers:
        Location:
          required: true
          schema:
            type: string
    400.BadRequest:
      description: Bad Request

You can reuse them if you don't need to modify or add response body:

paths:
  /dummy:
    get:
      "201":
         $ref: shared.yml#/components/responses/201.Created

But you can't reuse it if you need to specify your response body:

paths:
  /dummy:
    get:
      "400":
        allOf:  # not valid OpenAPI spec
          - $ref: shared.yml#/components/responses/400.BadRequest
          - responseBody:
            ...

Seems like right now the only way to get this to work is using Overlay. But that is not implemented in the wild and is very complicated.

jeremyfiel commented 1 year ago

Another workaround if you love copy and paste is to define all possible http operations and only define 405 as a valid response code.

{
    "openapi": "3.0.3",
    "info": {},
    "paths": {
        "/v1/the-best-api-endpoint": {
            "trace": {
                "responses": {
                    "405": {
                        "description": "method not allowed",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "message": "you can't submit this request"
                                }
                            }
                        }
                    }
                }
            },
            "options": {
                "responses": {
                    "405": {
                        "description": "method not allowed",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "message": "you can't submit this request"
                                }
                            }
                        }
                    }
                }
            },
            "patch": {
                "responses": {
                    "405": {
                        "description": "method not allowed",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "message": "you can't submit this request"
                                }
                            }
                        }
                    }
                }
            },
            "get": {
                "parameters": {},
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "thing": ""
                                }
                            }
                        }
                    },
                    "500": {
                        "description": "Server Error",
                        "content": {
                            "application/problem+json": {
                                "schema": {
                                    "errorDetails": ""
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
DerDu commented 1 year ago

We currently (3.0) using the go to method to achieve "less" copy past:

Definition:

components:
    responses:
        401:
            description: |
                The authorization header is missing

                The authorization token used is not valid
            content:
                application/json:
                    schema:
                        type: object
                        properties:
                            code:
                                type: number
                                example: 401
                            message:
                                type: string
                                example: 'Unauthorized'
                            content:
                                type: string
                                example: 'The reason for the refusal'

Usage:

paths:
    /url:
        get:
            responses:
                401:
                    $ref: '#/components/responses/401'

And to "customize default responses" we sneak them in as components/schemas not components/responses as you can't override response content https://github.com/OAI/OpenAPI-Specification/issues/521#issuecomment-1234713377 as you actually can in schemas:

Definition:

components:
    schemas:
        401:
            type: object
            properties:
                code:
                    type: number
                    example: 401
                message:
                    type: string
                    example: 'Unauthorized'
                content:
                    type: string
                    example: 'The reason for the refusal'

Usage:

paths:
    /url:
        get:
            responses:
                401:
                    description: |
                        The authorization header is missing

                        The authorization token used is not valid
                    content:
                        application/json:
                            schema:
                                allOf:
                                    -   $ref: '#/components/schemas/401'
                                    -   type: object
                                        required:
                                            - content
                                        properties:
                                            content:
                                                type: string
                                                example: 'Something else than: The reason for the refusal'

So we may have both if really necessary.. but native support would be much appreciated.. pretty please with extra sugar on? ;-)

MikeRalphson commented 1 year ago

I'm confused, sorry. Native support for what exactly? You can't use allOf outside a schema, and this is very unlikely to change.

DerDu commented 1 year ago

I'm confused, sorry. Native support for what exactly? You can't use allOf outside a schema, and this is very unlikely to change.

For us it makes "no sense" to distinguishe between schemas and responses. (depending on usecase)

so why is it that

I would like to see either the possibility to customize responses (somewhat) like schemas or to mark schemas as responses (so the won't be seen as DTOs) (hence native support)

MikeRalphson commented 1 year ago

I'm afraid I still don't follow. A response object is basically a lightweight wrapper around one or more schema objects. What is it you can't do today?

DerDu commented 1 year ago

Maybe i'am bad with explanations :D .. i wan't to achieve what comment https://github.com/OAI/OpenAPI-Specification/issues/521#issuecomment-1234713377 says it can't be done ;)

MikeRalphson commented 1 year ago

@DerDu unfortunately that comment has a ... in the example just where it would explain what it is trying to achieve....

unional commented 1 year ago

that comment has a ... in the example just where it would explain what it is trying to achieve

Hi, the ... literally means adding anything specific for that usage.

Using that example, 400.BadRequest only describes the HTTP Status that it is a bad request. i.e. the user pass in something that does not recognized or accepted by the endpoint. What could they be? That's specific to every usage.

e.g. customer-id is missing, item-count can't be negative number, etc.

Without the ability to use allOf at the response level, none of the response can be reused when we need to do any customization tailors to each usage.