I’ve already talked a bit about context values, and when not to use them. For a recap, take a look at these previous posts, so I don’t have to rehash those points today:
So from here on out, we’re assuming that you have a legitimate reason to store values in a context. How can/should you go about it? Read on!
type Context
type Context interface { … // Value returns the value associated with this context for key, or nil // if no value is associated with key. Successive calls to Value with // the same key returns the same result. // // Use context values only for request-scoped data that transits // processes and API boundaries, not for passing optional parameters to // functions.
We’ll stop here, to introduce a simple example. Let’s say you want to store the id of an authenticated user in the context, for use in various HTTP handlers—a very reasonable thing to do.
// Add the user ID to the context...
ctx := context.WithValue(ctx, "user_id", userID)
Then later, to retrieve that value, in an HTTP handler, for instance:
userID, ok := ctx.Value("user_id").(string)
if !ok {
return errors.New("no user ID found")
}
A couple things to note:
- The return type of
ctx.Value(...)
is the empty interface (any
), thus necessitating a type assertion (unless the value you’ve retrieved is usable as anany
, of course). - Both the getter (
ctx.Value(...)
and setter (context.WithValue(...)
) depend on the key ("user_id"
in this case). It’s best to define that in a single place. Aconst
would do in this case, but there are better alternatives we’ll get to soon.