OAI / OpenAPI-Specification

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

Support an operation to have multiple specifications per path (e.g. multiple POST operation per path) #182

Closed DavidBiesack closed 4 months ago

DavidBiesack commented 9 years ago

with POST actions especially, there can be several unrelated operations that would be better presented to the user as separate POST actions in swagger-ui because they do very different things to the same resource. Each of these different operations should have a unique description string and unique media types to select from and other unique parameters (such as query parameters), and thus have separate presentation in swagger-ui. By simply allowing only just schema overloading, there is no way for me to constrain query parameter A to be used with just media type X, and query parameter B to be used with media type Y. These are implemented as two independent operations and it would be nice to be able to model them independently in Swagger.

So I think a proposal i saw elsewhere to annotate the operations themselves (to provide unique keys in the JSON object) would actually be more flexible than other workarounds to the fact that Swagger only allows one POST per path when a REST API may in fact support many independent POST calls.

i.e. something like

paths:
 /a/b/c:
   get: ....
   put: ...
   post.optimize: spec for the optimize operation
   post.merge: spec for the merge operation

(Initially discussed in #146)

maxlinc commented 9 years ago

Real world example - OpenStack Server Actions. I've been trying to convert OpenStack WADL to Swagger and these operations have been a sticking point. There's no real way to describe them right now, because the Swagger doesn't allow path (which is what the WADL uses), nor does it allow "oneOf" or "anyOf" schemas. So I don't see any possible way to describe these services right now.

On the other hand, I want Swagger to define an API, not just describe it. That's the whole reason the working group decided to avoid some of these features in the first place - to avoid ambiguity. If this is going to be done it needs to be done in a way that works for:

It's basically a routing problem: given an HTTP request you should know what operation is being called, and this makes it ambiguous.

szhem commented 9 years ago

+100!

Recently we had to change our api because were unable to define multiple post methods per path. So api became uglier in favour of its documentation.

earth2marsh commented 9 years ago

This is a feature of Swagger's opinion on APIs. For better or worse, it presumes that the signature of an operation is the resource path pattern plus the HTTP verb.

To change this would require an alternate mechanism for defining the signature. If we do pick this up in Swagger.next, then let's consider an overloading of a method with some sort of signature property. I'm not sure that this is something that it SHOULD do, but that is how I would tackle it. (and I agree with what @maxlinc said above)

chrisregnier commented 9 years ago

I recently came across the same problem and would love to have the ability to define the API and associate the same path with multiple endpoints that are still unique.

So I'd like to suggest that endpoints are not defined by their paths, but by a user defined key name. More than likely it'll be a domain specific operation name (eg: 'addBookByJson','addBookByBinary' may both have the same path but different endpoints/consumes). Then each endpoint would have a path associated with it instead of 'being' the path directly. Ambiguity is still easy to check based on an equality function of all defined endpoints (which could then be based on implementing platform which might be more applicable rather than defining the equality relation in the swagger API).

There are so many ways I could define an endpoint based on an HTTP request. And if swagger is to be a general tool for documentation, then I would much rather see swagger show its opinions in the form of defaults (or the easy path), NOT by limiting functionality when I need to go outside of the norm to support others or implement new ideas!

theage commented 9 years ago

+1

eli-jordan commented 9 years ago

+1 This would make the tool much more fliexible. I totally agree with @earth2marsh on this point. Allow the user decide what properties of an http request determine its signature.

haidaraM commented 8 years ago

+1

fabriciorissetto commented 8 years ago

+1

eirnym commented 8 years ago

+1

who commented 8 years ago

+1

This would be really fantastic:

{
    "in": "body",
    "name": "abstractThing",
    "schema": {
        "oneOf": [
            {
                "$ref": "#/definitions/ConcreteThing"
            },
            {
                "$ref": "#/definitions/ConcreteOtherThing"
            }
        ]
    }
}
JosiasStraesser commented 8 years ago

+1

achingbrain commented 8 years ago

+1

Recently we had to change our api because were unable to define multiple post methods per path. So api became uglier in favour of its documentation.

Feels a bit like the tail wagging the dog.

Joyce-Stack commented 8 years ago

+1

tom-squires commented 8 years ago

+1

jenarros commented 8 years ago

+1

DavidBiesack commented 8 years ago

What we are doing in the interim is to use #tag in the paths to differentiate these.

/a/b/c: post: /a/b/c#merge: post:

We have customized Swagger UI to hide these tags and remove them from the Try It/curl actions

Each of these post operations can have their own parameters/produces/consumes.

I realize that almost none of the existing Swagger ecosystem will work with this, but we need to move forward, and this is the path we're taking. It was the easiest and lowest impact change to Swagger UI and the swagger documents, and it works fairly well. Our expectation is to be able to transform our use to wherever Swagger.Next goes.

gavincornwell commented 8 years ago

+1

webron commented 8 years ago

Parent: #574, #586.

jtaylor10 commented 8 years ago

Another possible format for modelling this, not perfect though either. It comes out of the REST principle that you use the verb. Now REST over HTTP forces verb to be GET,POST,etc and they suggest you use an _method parameter or some override parameter to POST operations to indicate your real verb. So with that in mind we could define a paramter with a special type or mark it someway as your verb-override parameter for the specific end point and then change the verb to what you want.

Would look something like this:

paths:
   /some/path
      parameters:
           _method:
               type: string
               verb-override: true
      post:
           ....
      copy:
           ....
      merge:
           ....

With this, anything that falls outside of the standard HTTP verbs are modelled as POST /some/path?_method=copy. It could also then be used for those servers that only support PATCH or other standard HTTP but not as well supported verbs through a method override.

juan-quiver commented 7 years ago

+1

gdyrrahitis commented 7 years ago

+1

glen-84 commented 7 years ago

@gdyrrahitis Please use reactions now, instead of +1 comments.

jbuhacoff commented 7 years ago

I am really hoping that this proposal will be accepted, to index APIs by their logical name instead of path.

I have a set of existing APIs that offer various content-type/accept combinations to accommodate various clients and use cases, and it's not possible to describe them in one openapi 2.0 document.

My temporary solution is to just have a separate openapi document for each use case, so that the inputs and outputs are appropriately bound together. I had to factor out all of the common definitions to external files in order to minimize the boilerplate.

fehguy commented 7 years ago

This particular proposal is not for 3.0, however with https://github.com/OAI/OpenAPI-Specification/pull/798 you can now specify different input and output schemas based on content type. Please read through that and hopefully that will satisfy your use case.

cfineman commented 7 years ago

From my initial reading of this, #146, and #791 this appears to cover what many folks were asking for (might even be usable for some of the protobuf-encoding extensions suggested in #801 ??)

I'm not up to speed on the "opinionated" aspects of the OpenAPI model but the idea of generic overloading based on parameters makes me a bit uneasy. Having more strongly defined variants for consuming clients is certainly a good thing to strive for but I'm a bit leary of allowing idiosyncrasies of various controller binding models leaking through into a standard (essentially the UI vs implementation argument put forward by @DavidBiesack in #146 )

caitsithx commented 7 years ago

+1 what is the final status of this issue?

fehguy commented 7 years ago

@caitsithx see my comment https://github.com/OAI/OpenAPI-Specification/issues/182#issuecomment-250600331 for what is happening with 3.0

biancama commented 7 years ago

+1

ancane commented 7 years ago

+1

dalbrekt commented 7 years ago

+1

glen-84 commented 7 years ago

@ancane @dalbrekt Please use reactions now, instead of +1 comments.

jrrevy commented 6 years ago

Adding my 2 cents ;) :

I have such a case in my project, where I want to use kind of polymorphism around POST method. I would like to be able to add an item (e.g. a pet) or a collection of items (e.g. multiple pets). By convention POST /pets/ means adding one item on my pet collection, although my main need is to add a collection of pets.

I should be something like that (maybe wrong)

{
/pets/:
    post:
    "in": "body",
    "name": "PetCollection",
    "schema": {
        "oneOf": [
            {
                "$ref": "#/definitions/Pet"
            },
            {
                type: array
                items:
                  $ref: '#/definitions/Pet'
            }
        ]
    }

It could be a fine test to verify that one path leads to multiple operation, depending on content.

I really love the @DavidBiesack workaround. Mine is a bit more ugly but compliant :

{
/pets/bulk/
    post:
    ....
}

The other one is, obviously, to deal with collection every time, even though there is only one item in my collection. Maybe I'm was wrong aiming to be compliant with convention, don't hesitate to tell me.

It would be related to #333.

DavidBiesack commented 6 years ago

@jrrevy glad you like my suggestion... but for OpenAPI 3.0 you can do as you suggest, and use oneOf in your schema.

What you can't do is make a clear link between passing a single object with schema A (i.e. your singleton) and receiving a response with schema X vs. passing request schema B (i.e. your array input) and getting back schema Y. With oneOf, you can pass { oneOf: [A, B] } and specify the operation returns { oneOf: [X, Y] }. There is no way to express the constraint A -> X, B -> Y (or that A -> Y and B -> X are not possible.) This also applies to query parameters and others aspects that my proposal would solve - if you wish to allow a query parameter P with the collection POST but not allow P with the singleton post, the oneOf schema support does not help.

xenohunter commented 6 years ago

@DavidBiesack hello! Could you please share the code where you implemented that trick with hashtags if it's open source? We want to follow your steps as we need our API to process different requestBody objects in one path. Thank you in advance!

DavidBiesack commented 6 years ago

We don't have any open source/published solution. We use an internal swagger-codegen tool to generate our API doc and we handle the hashes there, but It's not appropriate for open source. Other tools (and there are many) do not support this notation, of course.

xenohunter commented 6 years ago

@DavidBiesack OK, thanks anyway! I guess we will implement something on our own then.

jeevarajan commented 6 years ago

@DavidBiesack Could you please share any info on how to customize swagger ui to remove #tag from the path in "try it out"/curl actions? It will be really helping.

MikeRalphson commented 6 years ago

@jeevarajan the cleanest way would be by providing a requestInterceptor - see the documentation here and ensure showMutatedRequest is set to true. Again, please follow up on an issue on the swagger-ui repository if you have any further problems, not here.

askpatrickw commented 6 years ago

I'm working with two major Integration Platform as a Services (IPaaS) providers who are using Swagger to define the connector to a service to use in a solution.

In using this approach to connect to my company's API, it becomes near impossible to define nice discrete actions on an API that has 'evolved' over time and may offer many similar actions in one endpoint. In an IPaaS Connector's actions, you want nice crisp succent outcomes with the parameters sent limited to just relevant ones. Not POST + a combination of parameters equals one action vs. another action. Yes, our API probably needs refactoring, but in every enterprise these same issues will exist. Given that, the ability to define different POST definitions as outlined above and in the linked issues would be of great benefit.

This issue and the linked issues propose a method.name or method-name approach. I also see other issues to add additional Operation Objects ( #325 TRACE, #1306 SEARCH). This seems to point to the need for a more extensible approach.

What if instead of specific Operation Objects (GET, PUT, POST...), there was a generic Operation object which had the VERB (maybe METHOD) as part of its schema and then an endpoint could have an array of items Operation.

paths:
    /some/path:
    operations:
        type: array
        items:
            $ref/definitions/operation

definitions:
    operation:
        type: object
        properties:
            method:
                type: string
                example: DELETE, GET, POST, PUT, SEARCH, TRACE, ... 
            ....
            All the existing stuff in Operation Object
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#operationObject

This would allow for extensibility (new Methods) and would also enable the overloading ability others (and I) would like to see.

ma499 commented 6 years ago

@xenohunter did you implement anything open source to strip the anchor tags?

DavidBiesack commented 6 years ago

I did this work at my previous employer. We did not contribute it back to OpenAPI because it is obvious it would not be accepted. We did not open source this.

xenohunter commented 6 years ago

@ma499 no, that turned out to be of lower priority so we have not started yet even.

goodwillhacking commented 6 years ago

+1

DwayneJengSage commented 6 years ago

+1

We accidentally created two different call patterns for the same verb and URL, and now we're stuck supporting both of them. It would be really nice if there were a way to model this in Swagger.

matt212 commented 5 years ago

any updates on same how to implement it across !

roytanmoy commented 5 years ago

+1

cbcye commented 5 years ago

+1

membersound commented 4 years ago

I'd love to see GET endpoints supporting overload parameters. Eg the parameters-schema could support oneOf. Suggestion as follows:

{
 "path": {
   "/overloaded:" {
     "get": {
       "parameters": [
     {
        "name": "req",
        "in": "query",
        "schema": {
        "oneOf": [
            {
                "$ref": "#/components/schemas/FirstThing"
            },
            {
                "$ref": "#/components/schemas/SecondThing"
            }
        ]
        }
     }
       ]
     }
   }
}
hkosova commented 4 years ago

@membersound your example is already supported in OpenAPI 3.0.

whitlockjc commented 4 years ago

Just so I don't forget this later, this is really about having different input/output representations based on some input parameter, like format=[simple|extended] where the format value dictates which schema to use for the input/put.