Proposal: support fragment identifier in path object
See original GitHub issueOpenAPI spec is design for modeling REST APIs, but in real world we may find some APIs are mixture of restful style and RPC style. Those RPC APIs may share same URI, but their schema or content of their request body or query parameters are different. It’s common to meet this problem when you try to model APIs that have been in your company for a long time. As far as I know OpenAPI spec cannot model those kind of APIs properly because the combination of verb+path uniquely identify an operation. I found that there are other people have similar problem with us:
https://github.com/swagger-api/swagger-core/issues/935 https://github.com/swagger-api/swagger-editor/issues/854
But we found that this problem can be solved by simply adding fragment identifier in path objects.
Here is the example. There are some RPC style APIs sharing same path /api/team/{team_id} and verb “POST”. Their request body may look like
// Add members
{"operation": "add members", "data": {"members": [1, 2]}}
// Remove members
{"operation": "remove members", "data": {"members": [3, 4]}}
(I know they are bad designed, but they do exist and we have to model them.) By default, tools like Swagger-UI/Editor or swagger code generators cannot handle this case properly because their path and verb are same. In order to model those APIs, we add a fragment identifier after path for each RPC APIs
/api/team/{team_id}#AddMember:
post:
...
/api/team/{team_id}#RemoveMember:
post:
...
And Swagger-UI/Editor will treat them as different paths after we add this fragment, so that we can now model these RPC APIs like other restful ones in swagger editor. Because standard HTTP clients (browsers, ajax, urllib/requests in python, etc) will automatically omit fragment in url when making reqeusts, even we add fragment in path object, tools like Swagger-UI/Editor or clients created from swagger code genenerators can still work properly. And that’s all we need to do.
Accoding to wikiepdia
In computer hypertext, a fragment identifier is a short string of characters that refers to a resource that is subordinate to another, primary resource. The primary resource is identified by a Uniform Resource Identifier (URI), and the fragment identifier points to the subordinate resources
I think it is reasonable to use fragment identifier this way in OpenAPI. And I hope this proposal can become parts of OpenAPI spec to help other people who have similar problems.
Issue Analytics
- State:
- Created 5 years ago
- Reactions:7
- Comments:38 (15 by maintainers)
Top GitHub Comments
@darrelmiller
Personally I’d advocate for natively supporting the pattern if it is considered in-scope for OpenAPI at all. URI Fragments have very well-defined behavior: They are purely client-side, and the exact fragment syntax and semantics are determined by the resource representation’s media type, not the protocol indicated by the URI scheme.
No library that correctly makes HTTP requests will include the fragment in the request-URI.
The implicit routing use cases here appear to be:
OAS describes headers, query parameters, and request bodies in different places, all separate from the path. Fragments are not addressed at all, as OAS is concerned with client-server communication, while fragments are part of media type specifications.
Given that this issue and its corresponding PR are not on @earth2marsh 's list of 3.0.3 candidates (#2130), I’m guessing this would be handled in 3.1 at the earliest. It’s not clear to me that even that “tack on a fragment” solution is sufficiently compatible to be put into 3.0.x at all (can anyone confirm that one way or the other?)
In OAS 3.1 we could solve this by adding a new OAS-specific schema extension keyword that could be used to correlate across all of these things. You would use a
oneOf
in the schema of each thing that needs to correlate, possibly with anif
/then
in each branch if you want to explicitly call out the predicate for the server to test.The extension keyword would be used in each
oneOf
branch to name it. Since that keyword would indicate that you are correlating things, anif
/then
alongside of the keyword would be taken as expressing the correlation predicate (there are other reasons you might use anif
/then
so it’s useful to disambiguate the desired behavior).If you want to forbid certain parameters or headers in a particular branch, you can set their schemas to
false
(which is the same as"not": {}
but with clearer intent).That’s all pretty hand-wavey. I can work up an example if there is interest.
Of course we could also solve this by restructuring the Path Item or Operation Objects, but that would have to wait until OAS 4.
@earth2marsh
That’s not true. In essence,
swagger
is just a formal document. Users can parse the document and generate code from it, all you need is to handle fragment (use withSpecification Extensions
) in path objects properly if you want to use it to generate server-side code.And I believe most of the users won’t have these problems because if you are seeking a solution to handle the problem discussed in this thread, then I can bet your server-side code is not generated from
swagger
document 😂From my experience,
swagger
is most useful as an API modeling/documentation tools and client-side codegens. By introducing fragment into path objects won’t break these features. And it also compatible with server-side codegen, all you need is to customize the codegen to handle these special cases.Cannnot model APIs whose path and HTTP method are the same is one of the deficiencies that cannot be workaround from external but to fix the OAS specification itself. And the beauty of fragment solution is that it is totally compatible with the current specification. If you don’t use it, it won’t break anything. If you need to use it, it works well with
swagger editor
and most client side codegens.We are looking forward to the new features introduced by OAS4. But before we reach that point I think it can be no harm by introducing this hack. It just works well to use with YAML templating tool
ytt
to reduce unnecessary redundancy code in our use case.