-
Notifications
You must be signed in to change notification settings - Fork 20
Expand file tree
/
Copy pathrequest_id.go
More file actions
69 lines (55 loc) · 1.97 KB
/
request_id.go
File metadata and controls
69 lines (55 loc) · 1.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/*
Copyright © 2024 Acronis International GmbH.
Released under MIT license.
*/
package middleware
import (
"net/http"
"github.com/rs/xid"
)
const (
headerRequestID = "X-Request-ID"
headerInternalRequestID = "X-Int-Request-ID"
)
// RequestIDOpts represents an options for RequestID middleware.
type RequestIDOpts struct {
GenerateID func() string
GenerateInternalID func() string
}
type requestIDHandler struct {
next http.Handler
opts RequestIDOpts
}
func newID() string {
return xid.New().String()
}
// RequestID is a middleware that reads value of X-Request-ID request's HTTP header and generates new one if it's empty.
// Also, the middleware generates yet another id which may be used for internal purposes.
// The first id is named external request id, the second one - internal request id.
// Both these ids are put into request's context and returned in HTTP response in X-Request-ID and X-Int-Request-ID headers.
// It's using xid (based on Mongo Object ID algorithm). This ID generator has high performance with pretty enough entropy.
func RequestID() func(next http.Handler) http.Handler {
return RequestIDWithOpts(RequestIDOpts{
GenerateID: newID,
GenerateInternalID: newID,
})
}
// RequestIDWithOpts is a more configurable version of RequestID middleware.
func RequestIDWithOpts(opts RequestIDOpts) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return &requestIDHandler{next: next, opts: opts}
}
}
func (h *requestIDHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
requestID := r.Header.Get(headerRequestID)
if requestID == "" {
requestID = h.opts.GenerateID()
}
ctx = NewContextWithRequestID(ctx, requestID)
rw.Header().Set(headerRequestID, requestID)
internalRequestID := h.opts.GenerateInternalID()
ctx = NewContextWithInternalRequestID(ctx, internalRequestID)
rw.Header().Set(headerInternalRequestID, internalRequestID)
h.next.ServeHTTP(rw, r.WithContext(ctx))
}