If a route is defined as

engine.POST("/endpoint/:id/something", ...)

Is it possible, somewhere in the gin.Context object, to retrieve the string "/endpoint/:id/something" (different from, for example "/endpoint/123/something".

Comment From: qimingweng

cc @moberemk

Comment From: q191201771

c.Request.URL.Path may satisfied for you

Comment From: qimingweng

@q191201771 I'm specifically asking for the string without the absolute parameters but the parameters defined with a colon. For example ":id" instead of "123"

Comment From: q191201771

   const path = "/endpoint/:id/something"
    e.GET(path, func(c *gin.Context) {
        log.Println(path)
        log.Println(c.Param("id"))
        log.Println(c.Request.URL.Path)
        c.Set("path", path)
        if p, exist := c.Get("path"); exist {
            log.Println(p)
        }
    })

Comment From: qimingweng

I'm hoping that gin stores the original string somewhere in the internals so that I don't have to manage path string management myself. Yes. I could keep it in variables or even print out the literal path within each route.

Comment From: javierprovecho

@qimingweng maybe engine.Routes() can help you... :wink:

EDIT: checkout https://godoc.org/github.com/gin-gonic/gin#Engine.Routes

EDIT: reopen if this doesn't help you.

Comment From: qimingweng

@javierprovecho Hi, I'm basically asking if there was a way to see, in the Context, how to get the RouteInfo of this request.

Short of parsing the current url request against all the routes in engine.Routes a second time, is there another way to find this info? If not, is there an exposed function to do that parsing?

Comment From: javierprovecho

@qimingweng no, there is no exported field or function to get that information on an active request. Why do you need to know that on request time? I'm sure there is a better way...

Comment From: qimingweng

We want to provide better logging on each request. But the url Path is too specific.

I suppose we could use a handler generator to encapsulate that data as we define the routes, but I would perfer if I didn't need to repeat code (usually repetition is where bugs come in). Also this requires a large overhaul of all existing routes.

Comment From: itsjamie

@javierprovecho I'm also doing this, specifically for instrumentation of the API with Prometheus, I'd like to label the path using the original string. Right now, you have to store the path in the handler, and then use that, which prevents you from being able to use inline gin.HandlerFunc.

Ideally, that path would be accessible on the Context.

Comment From: itsjamie

Essentially, I've created a middleware that sets it in the context to solve the problem for me that utilizes it. But it would be great to not have to duplicate it.

Ends up with a definition like

singular.POST(
    "/activate",
    middleware.PathInfo(singular.BasePath()+"/activate"),
    ctrl.activateUser,
)

Comment From: qimingweng

At https://github.com/edusight, we ended up writing a wrapper function to do this without repeating a string.

// We needed an interface because we attach handlers to both engines
// as well as route groups
type routerGroupOrEngine interface {
    BasePath() string
    Handle(string, string, ...gin.HandlerFunc)
}

func trackPath(path string) gin.HandlerFunc {
    return func(c *gin.Context) {
        t := time.Now()

        c.Next()

        latency := time.Since(t)

        // Logging some data however you want, in this case we care about the latency and the path
        logEntry(latency, path)
    }
}

func addRouteToRouteGroupOrEngine(group routerGroupOrEngine, httpType string, path string, handlers ...gin.HandlerFunc) {
    fullPath := group.BasePath() + path
    allHandlers := []gin.HandlerFunc{
        trackPath(fullPath),
    }

    // The double spread operator is a little awkward so if you have ideas I'm open to changing this
    group.Handle(httpType, path, append(allHandlers, handlers...)...)
}

Comment From: roychowdhuryrohit-dev

Is it possible to access the basepath from context?

Comment From: eastrd

If you want to get the complete raw string after domain, including the GET parameters and such: c.Request.URL.String()

Comment From: jackieli-tes

For those who are still searching for an answer, you can use c.FullPath(): https://pkg.go.dev/github.com/gin-gonic/gin#Context.FullPath

Comment From: sougat818

c.FullPath() doesn't seem to return the parameters. c.Request.URL.String() still does