-
Notifications
You must be signed in to change notification settings - Fork 6
/
middleware.go
92 lines (77 loc) · 2.23 KB
/
middleware.go
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package babyapi
import (
"log/slog"
"net/http"
"time"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/render"
)
var DefaultMiddleware = []func(http.Handler) http.Handler{
middleware.RequestID,
middleware.RealIP,
middleware.Recoverer,
}
func (a *API[T]) ApplyDefaultMiddleware(r chi.Router) {
for _, m := range DefaultMiddleware {
r.Use(m)
}
r.Use(a.logMiddleware)
}
func (a *API[T]) logMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
logger := slog.Default()
logger = logger.With(
"method", r.Method,
"path", r.RequestURI,
"host", r.Host,
"from", r.RemoteAddr,
"request_id", middleware.GetReqID(r.Context()),
)
ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor)
t1 := time.Now()
defer func() {
if r.URL.Path == "/metrics" {
return
}
logger.With(
"status", ww.Status(),
"bytes_written", ww.BytesWritten(),
"time_elapsed", time.Since(t1),
).Info("response completed")
}()
next.ServeHTTP(ww, r.WithContext(NewContextWithLogger(r.Context(), logger)))
})
}
func (a *API[T]) requestBodyMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
body, httpErr := a.GetFromRequest(r)
if httpErr != nil {
_ = render.Render(w, r, httpErr)
return
}
logger := GetLoggerFromContext(r.Context())
logger.Info("received request body", "body", body)
next.ServeHTTP(w, r.WithContext(a.NewContextWithRequestBody(r.Context(), body)))
})
}
func (a *API[T]) resourceExistsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
resource, httpErr := a.GetRequestedResource(r)
if httpErr != nil {
// Skip for PUT because it can be used to create new resources
if r.Method == http.MethodPut {
next.ServeHTTP(w, r)
return
}
_ = render.Render(w, r, httpErr)
return
}
logger := GetLoggerFromContext(r.Context())
logger = logger.With(a.IDParamKey(), resource.GetID())
logger.Info("got resource")
ctx := a.newContextWithResource(r.Context(), resource)
ctx = NewContextWithLogger(ctx, logger)
next.ServeHTTP(w, r.WithContext(ctx))
})
}