To everyone who's new here:
If you use RESTful-Style API, router of gin will be a TROUBLEMAKER!
The root of the problem is httprouter
I wrote my own "router". Example:
router.GET("/:first/:second/:third", ViewRouterThree)
Then in ViewRouterThree you access c.Param("first")
, second, or third to figure out which view you want to call and call it directly. Example:
func ViewRouterTwo(c *gin.Context) {
if c.Param("second") == "new" {
viewNewThreadForm(c)
return
} else if c.Param("first") == "recent" {
if c.Param("second") == "threads" {
viewRecentThreads(c)
return
} else if c.Param("second") == "posts" {
viewRecentPosts(c)
return
...
Crappy but it works fine. Of course having a decent router would be nice.
In my point, because Gin is based on httprouter (in pursuit of speed, a special algorithm is used.), there is no elegant solution that can maintain both speed and decent routing.
this is idiomatic, imo
/:second
/:second/:id
/:second/:id/:first
/:second/:id/:first/:thisshouldbethefirstinstead
reduces parsing
yes,I encounter problem of conflict between path and wildcard ,and need to rewrite the openapi spec...It is annoying while gin have some limit with restful api style url path.
That really unexpected while I use this have-most-star web server framework in go world
And there is no any warning about those limitation while user expected a full function router. :(
related issue: https://github.com/julienschmidt/httprouter/issues/73
@appleboy Are there plans to support alternatives to httprouter
that do not have this limitation? Currently it is difficult to build REST-ful services using Gin.
yes, the conflicts issue is annoy
my solutions are:
/path/static: RouterA
/path/:id: RouterB
/path/:id/values: RouterC
write like this:
"/path/:id": { if get(id) == "static" { RouterA} else { RouterB } }
"/path/:id/some": RouterC
"/path/some/static": RouterA
"path/:id/values": RouterB
change the route as:
"/path-some/static": RouterA
"/path/:id/values": RouterB
the first noe is not bad,
I did't find any good solution for the second one
I hope there would be a support of alternatives
Well, I have never thought a simple REST could cause problems like this.
Of course I can rewrite my router, but what the hell?
I would never have chosen Gin if I had known about this beforehand. Having to write my own router makes Gin worse than worthless. This needs to be configurable.
I ended up here because I have a similar issue, which gave me the same error.
I took a quick look at the code and it looks like Gin is creating a tree in memory with all routes. Because of that, there can't be overlap.
A different approach that would solve both this issue and mine would be instead to keep all routes in a slice, and then iterate through them on each request. This way, the router would stop on the first match, and it would allow to have routes that partially overlap too.
For example:
router.GET("/:second/:id/:first/:thisshouldbethefirstinstead", handler)
router.GET("/:second/:id/:first", handler)
router.GET("/:second/:id", handler)
router.GET("/:second", handler)
If you navigate to /foo/bar
, the router would first try to match it against /:second/:id/:first/:thisshouldbethefirstinstead
, which will fail. It would then try /:second/:id/:first
, and then finally find a match with /:second/:id
. Because there's a match, it will stop processing the other requests. Of course, in this case order matters.
Now, I know that the current implementation, based on a tree, has a bit more performance, as it does less lookups on each route.
In practice, however, this won't matter much: most apps have a small number of routes, and the difference in time should be negligible. Additionally, because requests are matched in order, developers could put the most common routes at the top, thus making very few lookups for most requests.
There's significant prior art for doing routing this way:
I wrote a simple router based on this principle that has the same routing interface as the Gin engine (GET, POST, etc.). My router creates a generic, catch-all handler for each method, while adding the "actual" routes as regular expressions to a slice. When a request is received, Gin calls the generic catch-all handler, which in turn cycles through the slice of regexps to find the "real" handler. The generic handler also handles adding route parameters to the Gin Context, where they can be read just as if the Gin router had gone directly to the handler.
It sucks to have to do this, but it does work.
I would never use gin for this reason.
This is a known issue and really need to be addressed, some kind of abstraction would be great.
https://github.com/gin-gonic/gin/issues/1432
here is another problem if you trying to use google pattern you will encountered. Httprouter can't escaped colons which is valid url character.
Guys please fix this! The library that has most stars should not have this kind of problems. My employers are considering firing me because of this bug, I really would appreciate you guys fixing this!
totally sucks, never would like to use it
Just hit the same problem everybody is having ... time to look to a different framework.
I ended up here because I have a similar issue, which gave me the same error.
I took a quick look at the code and it looks like Gin is creating a tree in memory with all routes. Because of that, there can't be overlap.
A different approach that would solve both this issue and mine would be instead to keep all routes in a slice, and then iterate through them on each request. This way, the router would stop on the first match, and it would allow to have routes that partially overlap too.
For example:
router.GET("/:second/:id/:first/:thisshouldbethefirstinstead", handler) router.GET("/:second/:id/:first", handler) router.GET("/:second/:id", handler) router.GET("/:second", handler)
If you navigate to
/foo/bar
, the router would first try to match it against/:second/:id/:first/:thisshouldbethefirstinstead
, which will fail. It would then try/:second/:id/:first
, and then finally find a match with/:second/:id
. Because there's a match, it will stop processing the other requests. Of course, in this case order matters.Now, I know that the current implementation, based on a tree, has a bit more performance, as it does less lookups on each route.
In practice, however, this won't matter much: most apps have a small number of routes, and the difference in time should be negligible. Additionally, because requests are matched in order, developers could put the most common routes at the top, thus making very few lookups for most requests.
There's significant prior art for doing routing this way:
- Express: https://github.com/expressjs/express/blob/master/lib/router/index.js#L136
- Hapi: https://hapi.dev/api/?v=20.0.0#path-matching-order
- Even my own front-end router svelte-spa-router: https://github.com/ItalyPaleAle/svelte-spa-router/blob/master/Router.svelte#L445
Is there any intention to make something like this an opt-in configuration possibility if the 'raw speed' aspect of the original source of the issue is not to be resolved?
I think it makes a strong case that for some notion of fully RESTful adherence as a perf trade-off that can be switched on is a way to make an inroad to the issue the users could live with.
Hi guys, any updates about this issue?
Is this issue still persist now? just wondering. Still amazed that the most starred framework for its kind has this kinda problem.
yes, the issue is still an issue.
On Tue, 15 Dec 2020 at 07:00, Ridwan Afwan Karim Fauzi <
[email protected]> wrote:
Is this issue still persist now? just wondering. Still amazed that the
most starred framework for its kind has this kinda problem.—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/gin-gonic/gin/issues/2016#issuecomment-745096450, or
unsubscribe
https://github.com/notifications/unsubscribe-auth/AIDTGVHYCTHJZC7NLZD7AVLSU4CPFANCNFSM4IL5IANA
.
--
[image: SWORD health] https://swordhealth.com/
Tiago Cardoso
Software Engineer | SWORD Health https://swordhealth.com/
+351 911 977 902 <+351912345678>
[image: Skype] [image: LinkedIn]
https://pt.linkedin.com/in/tiagocardosoweb
Disclaimer:
The sender of this message cannot ensure the security of its electronic
transmission and consequently does not accept liability for any fact which
may interfere with the integrity of its content.
Would love to see this issue resolved, but if it's not possible, or not on the roadmap it'd be a good idea to disclose this routing limitation prominently in the README. This format of nesting is standard in RESTful APIs and I will need to consider ripping Gin out of the repo because of this.
Been tracking this issue for a while, and it seems like the problem is not just changing the router, is the performance impact that can happen after that. which seems irrelevant when you cannot comply with the standards. ripping out the lovely Gin is much harder than fixing this issue, but the pain of not having a standard router is convincing me to choose the harder approach.
I would argue that the performance impact is irrelevant regardless. Micro-optimizations in the router is likely not what will make or break your app's performance overall.
In the Node.Js space, Eran Hammer wrote this, which is definitely controversial but an interesting perspective: https://web.archive.org/web/20171017173141/https://medium.com/@eranhammer/when-500-faster-is-garbage-553121a088c3
Most helpful comment
Guys please fix this! The library that has most stars should not have this kind of problems. My employers are considering firing me because of this bug, I really would appreciate you guys fixing this!