{
  "$type": "site.standard.document",
  "canonicalUrl": "https://rednafi.com/shards/2026/03/user-id-through-context/",
  "description": "Why the middleware-to-handler boundary is a special case for context values.",
  "path": "/shards/2026/03/user-id-through-context/",
  "publishedAt": "2026-03-18T00:00:00.000Z",
  "site": "at://did:plc:fgtm2c26vfcj74rfmeggbyqj/site.standard.publication/3mnl6f7ob462z",
  "tags": [
    "Go",
    "API",
    "Distributed Systems"
  ],
  "textContent": "[Paweł Grzybek] reached out after reading [What belongs in Go's context values?] with a\nquestion about their auth [middleware] and the [handler] that reads the user ID from\ncontext:\n\n> I validate the session in middleware, and the session record in the DB holds the user ID,\n> which I put in the context for handlers to use later. According to your post, this is an\n> antipattern because the handler can't work without that value. But if I don't use context\n> here, I'd have to hit the sessions table again in the handler. Is this actually wrong, and\n> if so, how do I avoid the double DB lookup?\n\n---\n\nThe litmus test from the previous shard says:\n\n> If your code cannot proceed without some value, that value should not go in a context.\n\nThe reader's handler cannot create a resource without the user ID. So on a strict reading,\nthis looks like it fails the test.\n\nBut the test is about function signatures you control. When you write a regular Go function,\nyou can put userID uuid.UUID in its parameter list, and any caller knows the function\nrequires it. The middleware-to-handler boundary in net/http is different. Your handler is\nalways func(http.ResponseWriter, *http.Request). You can't add parameters to it. Context\nis how net/http middleware passes data to handlers, and that's by design.\n\nThe middleware already has to look up the session token to verify the request is\nauthenticated. The user ID comes out of that same lookup. Passing it along through context\navoids a second round trip to the DB for something the middleware already resolved.\n\nThe previous shard listed \"authentication tokens for middleware propagation\" as\ncontext-appropriate. A user ID extracted from a validated session token is the resolved form\nof that authentication. It's request-scoped, it comes from the auth layer, and every request\nthat reaches the handler has one because the middleware enforced it. It fits.\n\nTheir [middleware] does this:\n\nAnd the [handler] consumes it:\n\nThe middleware looks up the session once, stashes the user ID in context, and the handler\nreads it from there.\n\nIf context weren't an option, another way to avoid the repeated DB hit would be to cache the\nsession behind something like Redis. Multiple cache lookups are cheaper than multiple DB\ncalls. But for this case that's overkill, and you'd still pay the cost of a TCP round trip\nper lookup if the cache lives out of process.\n\n\n\n\n[Paweł Grzybek]:\n    https://bsky.app/profile/pawelgrzybek.com\n\n[What belongs in Go's context values?]:\n    /shards/2026/03/what-belongs-in-go-context-values/\n\n[middleware]:\n    https://github.com/hreftools/api/blob/2705fea8b1a508e00d35d248f16c063de353ef2d/internal/middlewares/auth.go#L62\n\n[handler]:\n    https://github.com/hreftools/api/blob/2705fea8b1a508e00d35d248f16c063de353ef2d/internal/handlers/resourcesCreate.go#L53",
  "title": "Is passing user ID through context an antipattern?"
}