10

I have a very simple piece of code. One single middleware is applied to all routes. In this middleware, the header field 'x-sentinel-tenant' is read. If it is blank, an error is returned. If it has some value, then that value is to be extracted and set in the request context for later use.

Here's my middleware code

// VerifyTenant ensures that the user has added tenant information in the header
func VerifyTenant(c *gin.Context) {
    requestTenant := c.Request.Header.Get("x-tenant")
    if requestTenant == "" {
        c.AbortWithStatusJSON(
            http.StatusBadRequest,
            views.GenerateErrorResponse(
                http.StatusBadRequest,
                "Please add tenant in the header.",
                c.Request.URL.Path,
            ),
        )
        return
    }
    c.Request = c.Request.WithContext(context.WithValue(c, tenant, requestTenant))
}

When I try to access this context in a later part of my code, here's how I get the data when hovered over the ctx value.

Please notice how there's a context within my context which is absurd

I am not sure what am I doing wrong. It's a fairly straight forward piece of code which is behaving very funny. Any leads will be appreciated. Thank you

When I update the context, I expect "tenant" to be added as another field. Which is not happening. Can multiple values not coexist in the same context?

My question - how to correctly set multiple values in gin request context Here's how I am trying to access tenant

return ctx.Value("Context").(context.Context).Value("tenant").(string)
Harshil
  • 436
  • 1
  • 7
  • 16
  • What is your actual problem? You provided a screenshot, and it is not obvious what's wrong with it. – zerkms Jun 29 '20 at 01:40
  • When I update the context, I expect "tenant" to be added as another field. Which is not happening. Can multiple values not coexist in the same context? – Harshil Jun 29 '20 at 01:57
  • "I expect "tenant" to be added as another field" --- and it's not happening? Why do you think so? Show your code that reads from the context. Also what exact value does the `tenant` variable hold? – zerkms Jun 29 '20 at 02:13
  • Btw, there is a special function `c.Set()`, then `c.GetString` – zerkms Jun 29 '20 at 02:25
  • I spent some more time and it seems that because there was some value added initially in the context, the other one's are now nested as context inside context. I am looking into that now. Updated the question to show how I am trying to access tenant. Looking into c.Set and c.GetString now.Thanks for the headsup – Harshil Jun 29 '20 at 02:32
  • I suppose I should modify my question to how to store and retrieve multiple values in the same context. I am using go-auth-middleware and that store a value "user" internally. Then when I try to add tenant, it seems to nest a context within a context. Any clue on how to extract stored values? – Harshil Jun 29 '20 at 02:40
  • `c.Set` and `c.GetX`? – zerkms Jun 29 '20 at 02:41
  • c.Set and c.Get does set the context but in the same format as seen above. Context within a context. That is something I am not sure how to solve. – Harshil Jun 29 '20 at 02:48
  • It's hard to understand what you mean `c.Set()` and `c.GetString()` should just work. Show your exact code that uses them then explain what problems you still have with it. – zerkms Jun 29 '20 at 02:49
  • Pardon me. If you see the question again, the screenshot shows what values are stored inside context. Using c.Set does the exact same thing. Nests a context within a context. So c.Set helps me set desired values in the context but I don't know how to retrieve them given a context.Context and not gin.Context – Harshil Jun 29 '20 at 02:56
  • It `c` is a `context.Context`, then just `c.Value()`? – zerkms Jun 29 '20 at 04:03
  • This solved the problem - https://play.golang.org/p/OJg9yrT0oJl Thanks for all the help @zerkms appreciate it – Harshil Jun 29 '20 at 04:37

1 Answers1

16

https://pkg.go.dev/github.com/gin-gonic/gin?tab=doc#Context.Set

func (*Context) Set does exactly what you want. an example is:

func VerifyTenant(ctx *gin.Context) {
    requestTenant := ctx.GetHeader("x-tenant")
    if requestTenant == "" {
        // Abort
        return
    }
    ctx.Set("x-tenant", requestTenant)
}

func Test(ctx *gin.Context){
    // when you need to get the value of "x-tenant"

    requestTenant := ctx.GetString("x-tenant")
}

Arith
  • 372
  • 1
  • 8