-
Notifications
You must be signed in to change notification settings - Fork 0
/
based_gorilla.go
107 lines (92 loc) · 2.57 KB
/
based_gorilla.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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package servers
import (
"encoding/json"
"fmt"
"log/slog"
"net/http"
"github.com/gorilla/mux"
)
type handleFunc[TIn, TOut any] struct {
handler func() (TOut, error)
handlerV func(vars map[string]string) (TOut, error)
handlerR func(request TIn) (TOut, error)
handlerRV func(request TIn, vars map[string]string) (TOut, error)
}
func (h *handleFunc[TIn, TOut]) validate() error {
handlers := 0
if h.handler != nil {
handlers++
}
if h.handlerV != nil {
handlers++
}
if h.handlerR != nil {
handlers++
}
if h.handlerRV != nil {
handlers++
}
if handlers == 1 {
return nil
}
return fmt.Errorf("exactly one handler must be set")
}
func unifiedRouteHandler[TIn any, TOut any](
r *mux.Router,
log *slog.Logger,
method HttpMethod,
url string,
handler handleFunc[TIn, TOut],
responseWriter func(w http.ResponseWriter, r *http.Request, response TOut) error,
) {
requireBody := handler.handlerR != nil || handler.handlerRV != nil
if err := method.validateBody(requireBody); err != nil {
panic(err)
}
if err := handler.validate(); err != nil {
panic(err)
}
r.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) {
defer panicRecovery(log, r, w)
var err error
var response TOut
switch {
case handler.handler != nil:
response, err = handler.handler()
case handler.handlerV != nil:
vars := mux.Vars(r)
log.Info("handle request", slog.String("url", r.RequestURI), slog.Any("vars", vars))
response, err = handler.handlerV(vars)
case handler.handlerR != nil:
var request TIn
err = json.NewDecoder(r.Body).Decode(&request)
if err != nil {
writeErrorResponse(log, r, w, ToBadRequestError(err))
return
}
defer r.Body.Close()
log.Debug("request body", slog.String("url", r.RequestURI), slog.Any("body", request))
response, err = handler.handlerR(request)
case handler.handlerRV != nil:
vars := mux.Vars(r)
log.Info("handle request", slog.String("url", r.RequestURI), slog.Any("vars", vars))
var request TIn
err = json.NewDecoder(r.Body).Decode(&request)
if err != nil {
writeErrorResponse(log, r, w, ToBadRequestError(err))
return
}
defer r.Body.Close()
log.Debug("request body", slog.String("url", r.RequestURI), slog.Any("body", request))
response, err = handler.handlerRV(request, vars)
}
if err != nil {
writeErrorResponse(log, r, w, ToInternalError(err))
return
}
if err = responseWriter(w, r, response); err != nil {
writeErrorResponse(log, r, w, ToInternalError(err))
}
log.Debug("request response", slog.String("url", r.RequestURI))
}).Methods(string(method))
}