gin-gonic / gin

Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.
https://gin-gonic.com/
MIT License
78.88k stars 8.02k forks source link

ctx.Keys is overwritten by obj in methods like ctx.HTML #4022

Open Yiannis128 opened 3 months ago

Yiannis128 commented 3 months ago

Description

If you have middleware (using r.Use()), you can set keys through the method ctx.Set(k, v) which puts them into ctx.Keys. This sets the expectation of when using:

ctx.HTML(http.StatusOK, "account.html", gin.H{
    "Name":  user.Name,
    "Email": user.Email,
})

You expect that the map gin.H's entries will be applied on top of ctx.Keys, however, it overwrites them. Here is my Use method:

r.Use(func(ctx *gin.Context) {
// Set common context values
ctx.Set("Title", "My website")

if cookieId, err := ctx.Cookie(data.COOKIE_SESSION); err == nil {
    ctx.Set("SignedIn", len(cookieId) > 0)
}
})

Here are some of my routes:

Route /

r.GET("/", func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "index.html", ctx.Keys)
})

Route about

r.GET("/about", func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "about.html", gin.H{})
})

Inside each one I simply output the context using {{.}}, the context is as follows:

Multitemplate

I am using the github.com/gin-contrib/multitemplate plugin as I need to use multiple templates, and it's recommended in the docs to use that. I am assuming that it's working as intended.

Environment

RedCrazyGhost commented 3 months ago

Although Conetxt.Keys and gin.H are both map[string]any, Keys are only used during the lifetime of the request and should not be exported as a result. gin.H is a specific output structure with multi-type support.

I suggest you use the code below to process the results and do something with the output

r.GET("/", func(ctx *gin.Context) {
   var mergeData gin.H
   for k, v := range ctx.Keys {
      mergedData[k] = v  // Process merge data
   }
   ctx.HTML(http.StatusOK, "index.html", mergeData)
})
Yiannis128 commented 3 months ago

Maybe it would be worth updating the documentation to state that, since my first impression was that it was a way of setting messages to be sent from the middleware to the endpoint.