Storing request and session ID in context.Context considered bad?
Asked Answered
B

2

6

There is this excellent blog post by Jack Lindamood How to correctly use context.Context in Go 1.7 which boils down to the following money quote:

Context.Value should inform, not control. This is the primary mantra that I feel should guide if you are using context.Value correctly. The content of context.Value is for maintainers not users. It should never be required input for documented or expected results.

Currently, I am using Context to transport the following information:

  • RequestID which is generated on the client-side passed to the Go backend and it solely travels through the command-chain and is then inserted in the response again. Without the RequestID in the response, the client-side would break though.

  • SessionID identifies the WebSocket session, this is important when certain responses are generated in asynchronous computations (e.g. worker queues) in order to identify on which WebSocket session the response should be send.

When taking the definition very seriously I would say both violate the intention of context.Context but then again their values do not change any behavior while the whole request is made, it's only relevant when generating the response.

What's the alternative? Having the context.Context for metadata in the server API actually helps to maintain lean method signatures because this data is really irrelevant to the API but only important for the transport layer which is why I am reluctant to create something like a request struct:

type Request struct {
    RequestID string
    SessionID string
}

and make it part of every API method which solely exists to be passed through before sending a response.  

Barleycorn answered 27/2, 2017 at 5:14 Comment(6)
Isn't the code that pulls the request id out of the request and sticks it into the response the same code? Like the http handler, or a middleware perhaps?Orthoclase
@Orthoclase Yes, still—if the context gets lost or altered while being passed through it would break.Barleycorn
Functions that are called by the handler cannot alter the context. They can only derive new contexts but those are invisible to the handler.Orthoclase
@Orthoclase Your point being? If you replace it with a new context it is effectively altered, also if it is not passed on.Barleycorn
My point is that there is no way for any function to change or remove the request id from the context the handler sees, so adding it to the response reliably should be a non-issue. Also, nothing is forcing you to call ctx.Value() at the bottom of the handler to retrieve the request id. It should be in a local variable anyway: play.golang.org/p/afhnQKY6E4Orthoclase
In my opinion, injecting RequestID and SessionID to context is not a bad approach. RequestID and SessionID is just like an identity for the request. Same thing happens to opentracing. They inject unique id for each request through context. As long as the value injected to the context is about the request identity, i think it's okay. Francesc also describe it on his just for func videoAlamo
C
0

Based on my understanding context should be limited to passing things like request or session ID. In my application, I do something like below in one of my middleware. Helps with observability

if next != nil {
   if requestID != "" {
     b := context.WithValue(r.Context(), "requestId", requestID)
     r = r.WithContext(b)
   }
   next.ServeHTTP(w, r)
}
Chi answered 31/10, 2018 at 0:34 Comment(1)
Docs of WithValue say to not use strings as context keys - just something to be aware of.Ceto
W
0

The introduction of contexts says:

The set of goroutines working on a request typically needs access to request-specific values such as the identity of the end user, authorization tokens, and the request’s deadline.

A session id is nothing else but a value identifying the request user in order to authorize the response.

Wristband answered 29/4 at 14:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.