Gin: panic: wildcard route conflicts with existing children

Created on 5 Feb 2015  路  10Comments  路  Source: gin-gonic/gin

router.GET("/api/test/basic_data_set_link", control.GetBasicDataSetLink())
router.GET("/api/:user_id/requestedgroups", control.GetRequestedGroups()) 

the above two lines conflict, and cause panic.
but it seems no problem. so, what's wrong with my code ??
thanks.

Most helpful comment

I deleted those cursing comments, and hereby give out my solution, hopefully it would help people.

After all, it's your own project. You didn't force us to use it.

    router.GET("/v1/images/:path1", GetHandler)           //      /v1/images/detail
    router.GET("/v1/images/:path1/:path2", GetHandler)    //      /v1/images/<id>/history

func GetHandler(c *gin.Context) {
    path1 := c.Param("path1")
    path2 := c.Param("path2")

    if path1 == "detail" && path2 == "" {
        Detail(c)
    } else if path1 != "" && path2 == "history" {
        imageId := path1
        History(c, imageId)
    } else {
        HandleHttpError(c, NewHttpError(404, "Page not found"))
    }
}

All 10 comments

Hello @carr123 , this is not a problem or issue from Gin, is from httprouter instead because how its made.

I suggest the following:

// ...
router.GET("/api/:user_id/requestedgroups", control.GetRequestedGroups) 
// ...
    if strings.HasPrefix(c.Request.RequestURI, "/api/test/basic_data_set_link") {
        return control.GetBasicDataSetLink(c)
    } else {
        // your original "control.GetRequestedGroups" hanlder code ...
    }
// ...

Thanks @javierprovecho this is helpful (and thanks for this project it is great). I am wondering if httprouter is too simple for mainstream use, and if you guys plan to support other routers like https://github.com/dimfeld/httptreemux ? We have the same problem as carr123 and would prefer to avoid too many wrappers. Thanks.

@wrunk +1

@wrunk no plans at the moment, everything of gin is around httprouter, and so speed and performance. Thank you for discovering me httptreeremux, I liked it!, I should compare speed against httprouter, and if it doesn't go so much slower, I think I will give it a try.

Closing this issue.

Is there any plans to support httptreeremux soon ?

@javierprovecho @manucorporat https://github.com/gin-gonic/gin/issues/205#issuecomment-73032517 is really helpful for me, but how would you set different middleware for /:key (catch-all) and /admin? I think I've looked through all the relevant httprouter and gin issues

I deleted those cursing comments, and hereby give out my solution, hopefully it would help people.

After all, it's your own project. You didn't force us to use it.

    router.GET("/v1/images/:path1", GetHandler)           //      /v1/images/detail
    router.GET("/v1/images/:path1/:path2", GetHandler)    //      /v1/images/<id>/history

func GetHandler(c *gin.Context) {
    path1 := c.Param("path1")
    path2 := c.Param("path2")

    if path1 == "detail" && path2 == "" {
        Detail(c)
    } else if path1 != "" && path2 == "history" {
        imageId := path1
        History(c, imageId)
    } else {
        HandleHttpError(c, NewHttpError(404, "Page not found"))
    }
}

I need wildcard route at root, like /:any at my url shortener project. But gin not support it, so I use router.NoRoute.

This should not be closed, those solutions are not ideal. In my case, I have to use middleware in between, for example:

router.GET("/active", findActive)

router.Use(someMiddleware())

router.GET(":id", findByID)

It would be very cumbersome to deal with this using solutions above.

Edited:

I made a workaround like this:

router.Get("/:id", h.findActive, someMiddleware(), h.findByID)

And in findActive():

func (h handler) findActive(c *gin.Context) {
  id := c.Param("id")
  if id == "active" {
    active := h.service.FindActive(c.Request.Context())
    response.Success(c, active)
    c.Abort()
    return
  }
  c.Next()
}

However, I still find it ugly and not straight forward, hope Gin will implement someway else in future.

This should not be closed, those solutions are not ideal. In my case, I have to use middleware in between, for example:

router.GET("/active", findActive)

router.Use(someMiddleware())

router.GET(":id", findByID)

It would be very cumbersome to deal with this using solutions above.

Edited:

I made a workaround like this:

router.Get("/:id", h.findActive, someMiddleware(), h.findByID)

And in findActive():

func (h handler) findActive(c *gin.Context) {
  id := c.Param("id")
  if id == "active" {
    active := h.service.GetActive(c.Request.Context())
    response.Success(c, active)
    c.Abort()
    return
  }
  c.Next()
}

However, I still find it ugly and not straight forward, hope Gin will implement someway else in future.

This is great. I meet the similar problem:

  • /v1/user/self: basic auth
  • /v1/user/:id: public

The conflict panics.
This solution works for my issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

xpbliss picture xpbliss  路  3Comments

mdnight picture mdnight  路  3Comments

ghost picture ghost  路  3Comments

rawoke083 picture rawoke083  路  3Comments

lilee picture lilee  路  3Comments