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

Add default responses

Open fehguy opened this issue 8 years ago • 18 comments

Currently, every single operation must declare its' own responses. This causes a whole bunch of duplication, which would be better served by having a top-level responses section in the spec. Like the security construct, operations could override the default responses on their own.

fehguy avatar Feb 10 '16 21:02 fehguy

parent issue #560

fehguy avatar Feb 10 '16 21:02 fehguy

An alternative solution that could potentially also address this concern is to introduce the notion of a globally defined array of OperationTypes. In the same way that there can be redundancy in the responses that an operation returns, there can also be redundancy in the parameters that the operations accept.

By allowing the definition of a type of operation with the parameters and responses defined, we are creating the HTTP equivalent of a function signature definition, aka delegate.

An example of this might be in an issue tracking system where there following operations exist:

/api/issues/closed{?createdSince,limit,keywords} /api/issues/active{?createdSince,limit,keywords}

In both cases the result is a list of issues and the same set of parameters are valid.

One additional benefit of taking this approach is that it becomes easier to describe hypermedia systems that use link relation types. Consider the following example,

{ 
   "project" :"My software product",
   "links" : [
             { "rel" : "issues", "href": "/api/issues/closed{?createdSince,limit,keywords}", "title" : "closed" }
             { "rel" : "issues", "href": "/api/issues/active{?createdSince,limit,keywords}", "title" : "Active" }
       ]
}

The OpenAPI document could describe the expected behaviour when an issues type of operation is accessed.

darrelmiller avatar Feb 17 '16 01:02 darrelmiller

:+1: to @darrelmiller's suggestion.

dilipkrish avatar Feb 17 '16 01:02 dilipkrish

@darrelmiller You can do this example today, like this:

swagger: 2.0
...
x-operationTypes:
  IssueList:
    parameters:
      ..
    get:
      ..
    post:
      ..
paths:
  /api/issues/closed:
    $ref: '#/x-operationTypes/IssueList'
  /api/issues/active:
    $ref: '#/x-operationTypes/IssueList'

If the paths have parameters in them, you can still do this sort of thing in YAML, but not in JSON. Since this is already possible in OAS today, is it really necessary to add new features? Less is more.

mpnally avatar Feb 21 '16 06:02 mpnally

@mpnally That's definitely an interesting workaround even with the JSON limitation.

However, there is additional value to being explicit about the operation type. When it comes to creating client code, explicit knowledge of the similarity between the interaction mechanism for different resources can be leveraged to significantly reduce redundant client code. I have had considerable success in building client libraries where I create a client side class that implements the Operation Type behavior and then re-use that class for multiple resources.

This lends itself well to a hypermedia scenario where the link relation type can tell the client which operation type to use and the resource identifier is contained in the response. This allows client code to successfully interact with resources it previously did not know about even when there is a non-trivial interaction model.

I agree that adding unnecessary features is good design choice. However, in this case, I think the web architecture has proven that the notion of link relation types is a useful one and we have an opportunity to model that important web concept in OpenApi.

darrelmiller avatar Feb 21 '16 16:02 darrelmiller

@fehguy In Swagger 2.0 there is already a top-level responses object that is used for global responses definitions.

dolmen avatar Mar 01 '16 15:03 dolmen

@dolmen the top level responses are not used as global responses but as reusable responses to which you can reference from operations.

webron avatar Mar 01 '16 19:03 webron

@webron Yes. My use of "global" adjective was not right. But my point is that @fehguy proposal conflicts with an existing use of the responses property in Swagger 2.0.

dolmen avatar Mar 02 '16 00:03 dolmen

Good feedback on this. Two thoughts.

First, @darrelmiller's suggestion is interesting as it can be used to compose many different types into an operation. It could become very verbose still, as one could potentially have dozens of constructs in the path identifier. I'll keep thinking about how that could work.

Next, the notion of top-level definitions in the current 2.0 spec is a little confusing. For example as @dolmen pointed out, there is a responses section, but they're not really responses--they are responseDefinitions. But we have a top-level accepts which applies to all operations defined in the spec.

I think these are different considerations. To address the 2nd item, in general, we have definitions and implementations at the root of the specification. Think of definitions as items which are always referenced elsewhere, and implementations as instances of requirements in the definition itself.

Some definitions:

  • definitions
  • securityDefinitions
  • parameters
  • responses

Some implementations:

  • paths
  • accepts/consumes
  • info
  • security
  • host
  • schemes
  • basePaths
  • tags

This is very confusing. The purpose for named definitions was that the schema could be used to ensure that all items under the, say, parameters definition were valid.

To simplify the structure, and to make room for reusable components as well as a hierarchial structure, I propose the following:

  • The specification always supports a top-down overlay. This means that items defined at the top-level of the specification shall apply to all subordinate operations, except when overridden.
  • The specification defines an explicit section for schemas, with the goal of reuse

Proposed structural changes

# implementations
info:
  # info object

# some implementations omitted for clarity
basePath:
  # basePath
tags:
  # - tag object
paths:
  # paths object
parameters:
  # parameters which apply to all operations
responses:
  # responses which apply to all operations
responseHeaders:
  # headers to be returned in all responses
security:
  # security requirements which apply to all operations
# definitions
schemas:
  definitions:
    # payload definition objects
  parameters:
    # parameters objects
  responses:
    # responses objects
  responseHeaders:
    # headers returned in responses
  security:
    # security definitions

In the proposed structure, we now have a single schemas section which allows us to put all reusable components in a single section. It also makes it possible to have the new parameters and responses section, which will give maximum reusability and readability.

If a top-level response is defined, say with 404 as the key, then an operation can override it by defining a new 404 response definition. There is no deletion of top-level items inside an operation.

fehguy avatar Mar 14 '16 18:03 fehguy

@fehguy For the naming, I would prefer definitions as the top level, and schemas for payload schema definitions under that, instead of the other way around.

definitions:
  schemas:
    # payload schema definition objects
  parameters:
    # parameter definition objects
  responses:
    # response objects
  ...

I guess we could also have operations objects in there (as proposed in #577).

ePaul avatar Mar 14 '16 23:03 ePaul

@ePaul IMHO it very bad decision to change semantic of existing keyword. One thing is to put it in a different place of hierarchy and totally another is to change it mining. And it's not only for Swagger 2.0 migration, because Swagger borrowed it from JSON Schema, see this.

@fehguy I agree with @ePaul that schemas is confusing because of similarity with JSON Schema. Let's wait maybe someone come up with a better alternative.

IvanGoncharov avatar Mar 15 '16 00:03 IvanGoncharov

I kind of like the name schemas. It implies that that portion of the API description corresponds to something validatable using JSON Schema.

SandyChapman avatar Mar 22 '16 15:03 SandyChapman

@SandyChapman Yes, but that validatability (does that word exist?) works only for JSON stuff which is transmitted in body parameters or responses, i.e. which corresponds to model definitions. That was my reason for definitions/schemas. I understand that people don't like reusing the definitions name which was formerly used for just schema definitions, though.

ePaul avatar Mar 23 '16 18:03 ePaul

Please also see the discussion on #445 which discusses creating reusable parameter sets.

I see all these as related topics: how to get effective reuse of OAS constructs, either through composition and some form of template or protoypes mechanism, then providing a way to "mixin" those reusable elements, be they parameter definitions, responses, links, etc.

While much can be done with $ref, I would much prefer to see structural notation that conveys the abstraction. It would be nice to have a uniform way of defining and invoking mixins.

DavidBiesack avatar Apr 08 '16 16:04 DavidBiesack

A simple usecase, status code which apply to all paths: 401, 403, 500, 502, 503, 504. They -- in most cases -- don't require any response body. Maybe 500.

michael-o avatar Oct 18 '19 14:10 michael-o

A simple usecase, status code which apply to all paths: 401, 403, 500, 502, 503, 504. They -- in most cases -- don' require any response body. Maybe 500.

I second that. (it's 2021)

mxmlnglt avatar Jul 08 '21 20:07 mxmlnglt

+1

omgkotofey avatar Jul 13 '21 21:07 omgkotofey

I will take a look at if/how overlays can solve this problem. This is part of determining whether overlay spec is sufficient, so I won't comment on other solutions now.

For @michael-o 's question

  1. Using explicit http response codes
{
  "overlay": "1.0.0",
  "info": {
    "title": "Default Response Codes Overlay",
    "version": "1.0.0"
  },
  "actions": [
    {
      "target": "info",
      "update": {
        "x-overlay-applied": "default-response-codes"
      }
    },
    {
      "description": "Add default responses to all operations",
      "target": "paths.*.*",
      "update": {
        "responses": {
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden"
          },
          "500": {
            "description": "Internal Server Error"
          },
          "502": {
            "description": "Bad Gateway"
          },
          "503": {
            "description": "Service Unavailable"
          },
          "504": {
            "description": "Gateway Timeout"
          }
        }
      }
    }
  ]
}
  1. Using 'default' response, https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#responsesObject
{
  "overlay": "1.0.0",
  "info": {
    "title": "Default Response Overlay",
    "version": "1.0.0"
  },
  "actions": [
    {
      "target": "info",
      "update": {
        "x-overlay-applied": "default-response"
      }
    },
    {
      "description": "Add default response to all operations",
      "target": "paths.*.*",
      "update": {
        "responses": {
          "default": {
            "description": "unexpected error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "integer",
                      "format": "int32"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  ]
}

kscheirer avatar May 19 '22 19:05 kscheirer