-
Notifications
You must be signed in to change notification settings - Fork 9.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: support fragment identifier in path object #1635
Comments
The fragment identifier, correct me if I am wrong, is something that gets evaluated on the client side and not on the server. In the past, fragment identifiers have been used to maintain a client side only history and application state, and specific code needs to be in place in order to handle such. The server does not know about such fragment identifiers, see for example here: https://en.wikipedia.org/wiki/Fragment_identifier
So in order to be able to evaluate fragment identifiers on the server, your client side application will have to make them actual parameters of either REST call, e.g. parameter: fragment { type: string } |
@silkentrance You are right. I don't take server side into account because we only used code generators on client side. I do know that fragment identifiers only work on client side. The point here is we find that we can use fragment identifiers to further distinguish difference resources under same paths, by doing this we could have independent entries for those sub-resources in auto-generated clients. |
This would be so useful - especially in Role based Service APIs, where what OpenAPI considers a service identifier PS: Of course Role has no meaning in OpenAPI , but it is a common switch criteria of service behavior in current or legacy API designs. Examples:
|
This is both horrendous and ingenious at the same time. This would allow folks to model RPC style APIs where a single path tunnels multiple operations. However, we probably would need some way to correlate the value in the fragment with some value in the request body. Or at least support the notion of constant parameter values that allow the server to distinguish between the different operations. It does raise the question, do we allow this use of fragment identifiers and twist the definition of |
Are we talking about Link Objects here? Or Operations? It's pretty common for there to be a correlation between request body values and path or query string parameters, but we don't really describe that in Operations today.
ahem... modern JSON Schema |
const is a great idea for the case that using a enumerated field in request body to distinguish the operations. But for more complex cases I think we need a Turing complete JSON precondition DSL to decide which backend service should response to the request. I don't think there are exited tech can meet this requirement. IMHO, a more practical method is for endpoints that share same path, the server-side code generator should force the backend developer to implement a precondition(request)->boolean interface. And backend router should use both path pattern and result of precondition to decide what controller the request should be routed to. |
@link89, and others: I'm stuck with the same problem. I've one base path-URL and all APIs are listed under this, APIs have different query parameters. But, the response is not correct because the fragment identifier is attached to the request URL and curl request.
|
@ashish25cca You need to modify the codegen a little bit to workaround this problem. Most of swagger code generators do not handle fragments properly. They just concat query-string right after the path instead of moving fragment to the end of query-string. You can fix this in codegen by simply remove fragment before join with query-string. Or more formally, using URI class (which is part of stdlib of most programming languages and will handle this case correctly) instead of string operation. The problem you have occurred is the main motive I create this PR. Because the usage of fragment identifier is not covered by OpenAPI specification, most of codegen implementation don't take this into account (actually they should because it's covered by URI spec). But it's easy to workaround (with one or two lines of code changed), so I think you can try to fix it this way. |
@link89 : Thank you so much for your quick reply. Would be a great help if you kindly provide the steps to fix this in codegen? |
@link89 : I've downloaded swagger editor from below link and writing yaml for each API manually. https://github.com/swagger-api/swagger-editor If you can please let me know the file name with the required change? ,and thank you so much for your time : ) |
I guess you need to change I didn't test this by myself, you may give it a try and give me some feedback. Update: |
@link89 , thank you for your reply. However, I've tried changing code in node_modules/swagger-client/dist/index.js at line number 740 with below code:
var finalStr = joinSearch(newStr, encodeFormOrQuery(query));
But, no luck : ( still segment identifier is being added to request URL and curl request., please suggest further. Is there something I'm missing out. |
@link89, hey, I'm seriously missing something. So, this is I've done: 1). Downloaded swagger editor from this link: 2). Now, since node_modules are not present into this by default, I went to the director location through terminal and run 3). So, by now I have node_modules folder in my project, I changed code in node_modules/swagger-client/dist/index.js at line number 740
var finalStr = joinSearch(newStr, encodeFormOrQuery(query));
4). When I run it through local host, still fragment are not removed: Kindly suggest, would be a great help !! |
I guess you can try to rerun |
@link89, I've tried all but no luck, still, fragment is attached to request URL. It would be really great help. |
@link89 , Thank you so much for your help so far :) @darrelmiller , @iongion ,@silkentrance : guys I need help.. Please provide video for the same, if possible. |
@ashish25cca I guess you need to learn to fix this by yourself, for example adding some |
@link89, apologies to update on it so late. |
+1. We're designing a contextual API that changes spec depending on the current tenant, which is specified by a request header value. So the same endpoint might actually perform two different operations depending on this value. Every controller is thus mapped as such:
This issue is a deal-breaker because the frontend team relies on tools that generate Typescript controllers from a Swagger/OpenAPI spec. If we enable implicit routing the spec breaks, because now there are multiple controllers that point to the same path despite only one being able to answer the client at a time. For the time being, I'm either going to disable implicit routing when generating the spec or I'm going to write some fancy document processor for NSwag that ignores implicit routes. But it would be great if OpenAPI implemented some way of dealing with such ambiguities. |
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 The extension keyword would be used in each If you want to forbid certain parameters or headers in a particular branch, you can set their schemas to 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. |
Note that this approach could also be used for other sorts of correlations, such as correlating |
FWIW, I'm bearish on the idea that fragments have meaning here. If you consider that a spec is not a client-only artifact, such as using the spec to generate server-side code, then fragments are meaningless, since they're purely client-side. Happy to discuss and be enlightened, but I don't see that fragments belong in the spec, myself. |
See also #182 for how fragments can (be abused) to overcome OAS constraints. They need not be part of the actual routing/dispatch at runtime; the server can multiplex requests based on actual parameters. As Darrell says, horrendous and ingenious at the same time |
How do you propose that separate API operations be differentiated in the spec, then, if the Path and HTTP Method are the same? For reference, I've been trying to model AWS APIs like SNS or SQS using unmodified OpenAPI3 Schema and run into issues because every single API operation is I know it's a terrible design for APIs, but it's not like AWS APIs are going to fundamentally change any time soon and it's a shame that really just due to this issue I cannot properly use OpenAPI3 Schema to model these types of APIs without the fragment hack.. |
@jaypipes FWIW we use the fragment hack over at APIs-guru in documents such as https://github.com/APIs-guru/openapi-directory/blob/master/APIs/amazonaws.com/sns/2010-03-31/openapi.yaml |
That's not true. In essence, 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 From my experience, 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 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 |
The server can't see what fragment was used in the request. HTTP does not allow it. |
Even though I disagree with the fragment identifier, I do support exploring alternate signatures. If several API operations share an HTTP method and path pattern but can be identified by an attribute in the query string or payload, there might be other was to represent that. However, it is worth noting that this expansion would add some additional burden on tooling authors who would have a bigger surface area to support. |
Query parameters are part of the resource identifier. We need to get to a point where we can distinguish between PathItems using the query parameter. Probably one of the biggest stumbling blocks is the property name "paths". Once we get over that, we then have to deal with funky stuff like the significance of parameter order. Most people don't consider the query parameter order as significant, but as far as resource matching is concerned it is. This doesn't solve the problem of distinguishing operations by headers and request body content. But I think we need to solve this problem one bite at a time. |
Sure I know this and that's why I said to use with /api/teams/{teamId}#action=AddMembers:
post:
x-routing-condition-typescript: req.body.action == 'AddMembers'
...
/api/teams/{teamId}#action=DeleteMembers:
post:
x-routing-condition-typescript: req.body.action == 'DeleteMembers'
... And then you should customize the server-side codgen a little bit to make use of teamOperations(req: Request) {
if (req.body.action == 'AddMembers') // x-routing-condition-typescript
return this.addMembers(req);
if (req.body.action == 'DeleteMembers') // x-routing-condition-typescript
return this.deleteMembers(req);
return new ErrorResponse(400, 'Bad Request');
}
addMembers(req) {
...
}
deleteMembers(req) {
...
} Basically /api/teams/{teamId}#headers.operation==add-members:
post:
...
/api/teams/{teamId}#headers.operation==delete-members:
post:
... In essence,
Surely there are a lot of other ways to achieve the same suppose, but I think |
@link89 With well-designed extensions you don't need to abuse fragments like this. That's the whole point of my earlier comment: #1635 (comment) |
@OAI/tsc unless fragments are seriously under consideration for this, could we close this issue and file a new issue describing the problem rather than a (as far as I can tell) rejected solution so that discussion can be properly focused? |
Speaking just for myself, I'm not interested in trying to solve RPC issues before we address the issue of differentiating pathitems by query string. |
@darrelmiller is there a separate issue for that? It would be good to disentangle it from all of the fragment-related discussion. |
related: #182 ; see that. fragments are simply one mechanism people have used to deal with this (stemming from OpenAPI 2.0) |
I think this proposal - while shows a clever way to solve a real use case - may hinder interoperability and constraint the evolution of the spec. As many of you already said, fragment is not sent to the server. This is highlighted too in httpbis-semantics
imho:
|
I just found the following text
in https://www.rfc-editor.org/rfc/rfc8820.html#name-uri-fragment-identifiers |
I think this should end the discussion. |
'Fragment' should only have implications for ToLink and is not supported in the latest OpenAPI specs. - haskell-servant/servant#1324 (comment) - OAI/OpenAPI-Specification#1635
'Fragment' should only have implications for ToLink and is not supported in the latest OpenAPI specs. - haskell-servant/servant#1324 (comment) - OAI/OpenAPI-Specification#1635
'Fragment' should only have implications for ToLink and is not supported in the latest OpenAPI specs. - haskell-servant/servant#1324 (comment) - OAI/OpenAPI-Specification#1635
OpenAPI 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:
swagger-api/swagger-core#935
swagger-api/swagger-editor#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
(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
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
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.
The text was updated successfully, but these errors were encountered: