Open fehguy opened 8 years ago
parent issue OAI/OpenAPI-Specification#560
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.
:+1: to @darrelmiller's suggestion.
@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 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.
@fehguy In Swagger 2.0 there is already a top-level responses
object that is used for global responses definitions.
@dolmen the top level responses are not used as global responses but as reusable responses to which you can reference from operations.
@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.
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:
Some implementations:
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:
# 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 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 OAI/OpenAPI-Specification#577).
@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.
I kind of like the name schemas
. It implies that that portion of the API description corresponds to something validatable using JSON Schema.
@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.
Please also see the discussion on OAI/Overlay-Specification#34 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.
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.
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)
+1
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
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"
}
}
}
}
]
}
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"
}
}
}
}
}
}
}
}
}
]
}
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 thesecurity
construct, operations could override the default responses on their own.