package main
import (
"context"
"fmt"
"log/slog"
"net/http"
)
// Private key type — guaranteed unique across packages.
type ctxKey struct{ name string }
var (
userIDKey = &ctxKey{name: "user_id"}
requestIDKey = &ctxKey{name: "request_id"}
)
func WithUserID(ctx context.Context, id int) context.Context {
return context.WithValue(ctx, userIDKey, id)
}
func UserIDFrom(ctx context.Context) (int, bool) {
id, ok := ctx.Value(userIDKey).(int)
return id, ok
}
// Middleware that attaches an auto-generated request ID
func RequestIDMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
rid := "req-" + r.Header.Get("X-Request-ID") // or generate
ctx := context.WithValue(r.Context(), requestIDKey, rid)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
// Anywhere downstream
func handleRequest(w http.ResponseWriter, r *http.Request) {
rid, _ := r.Context().Value(requestIDKey).(string)
if uid, ok := UserIDFrom(r.Context()); ok {
slog.Info("handling", "request_id", rid, "user_id", uid)
}
fmt.Fprintln(w, "ok")
}
Create a free account and build your private vault. Share publicly whenever you want.