Files
httpx/server/middleware_requestid.go
Aleksey Shakhmatov 49be6f8a7e Add client RequestID middleware for cross-service propagation
Introduces internal/requestid package with shared context key to avoid
circular imports between server and middleware packages. Server's
RequestID middleware now uses the shared key. Client middleware picks up
the ID from context and sets X-Request-Id on outgoing requests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 21:47:58 +03:00

52 lines
1.4 KiB
Go

package server
import (
"context"
"crypto/rand"
"fmt"
"net/http"
"git.codelab.vc/pkg/httpx/internal/requestid"
)
// RequestID returns a middleware that assigns a unique request ID to each
// request. If the incoming request already has an X-Request-Id header, that
// value is used. Otherwise a new UUID v4 is generated via crypto/rand.
//
// The request ID is stored in the request context (retrieve with
// RequestIDFromContext) and set on the response X-Request-Id header.
func RequestID() Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
id := r.Header.Get("X-Request-Id")
if id == "" {
id = newUUID()
}
ctx := requestid.NewContext(r.Context(), id)
w.Header().Set("X-Request-Id", id)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}
// RequestIDFromContext returns the request ID from the context, or an empty
// string if none is set.
func RequestIDFromContext(ctx context.Context) string {
return requestid.FromContext(ctx)
}
// newUUID generates a UUID v4 string using crypto/rand.
func newUUID() string {
var uuid [16]byte
_, _ = rand.Read(uuid[:])
// Set version 4 (bits 12-15 of time_hi_and_version).
uuid[6] = (uuid[6] & 0x0f) | 0x40
// Set variant bits (10xx).
uuid[8] = (uuid[8] & 0x3f) | 0x80
return fmt.Sprintf("%x-%x-%x-%x-%x",
uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:16])
}