-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathadapter.go
140 lines (121 loc) · 3.48 KB
/
adapter.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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package crud
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"reflect"
)
type ServeMuxAdapter struct {
Engine *http.ServeMux
}
func NewServeMuxAdapter() *ServeMuxAdapter {
return &ServeMuxAdapter{
Engine: http.NewServeMux(),
}
}
type MiddlewareFunc func(http.Handler) http.Handler
func (a *ServeMuxAdapter) Install(r *Router, spec *Spec) error {
middlewares := []MiddlewareFunc{
validateHandlerMiddleware(r, spec),
}
switch v := spec.PreHandlers.(type) {
case nil:
case []MiddlewareFunc:
middlewares = append(middlewares, v...)
case MiddlewareFunc:
middlewares = append(middlewares, v)
case func(http.Handler) http.Handler:
middlewares = append(middlewares, v)
default:
return fmt.Errorf("PreHandlers must be MiddlewareFunc, got: %v", reflect.TypeOf(spec.Handler))
}
var finalHandler http.Handler
switch v := spec.Handler.(type) {
case nil:
return fmt.Errorf("handler must not be nil")
case http.HandlerFunc:
finalHandler = v
case func(http.ResponseWriter, *http.Request):
finalHandler = http.HandlerFunc(v)
case http.Handler:
finalHandler = v
default:
return fmt.Errorf("handler must be http.HandlerFunc, got %v", reflect.TypeOf(spec.Handler))
}
// install the route, use a subrouter so the "use" is scoped
path := fmt.Sprintf("%s %s", spec.Method, spec.Path)
subrouter := http.NewServeMux()
subrouter.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
handler := finalHandler
for i := len(middlewares) - 1; i >= 0; i-- {
handler = middlewares[i](handler)
}
handler.ServeHTTP(w, r)
})
a.Engine.Handle(path, subrouter)
return nil
}
func (a *ServeMuxAdapter) Serve(swagger *Swagger, addr string) error {
a.Engine.HandleFunc("GET /swagger.json", func(w http.ResponseWriter, r *http.Request) {
_ = json.NewEncoder(w).Encode(swagger)
})
a.Engine.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("content-type", "text/html")
_, err := w.Write(SwaggerUiTemplate)
if err != nil {
panic(err)
}
})
return http.ListenAndServe(addr, a.Engine)
}
func validateHandlerMiddleware(router *Router, spec *Spec) MiddlewareFunc {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
val := spec.Validate
var query url.Values
var body interface{}
var path map[string]string
if val.Path.Initialized() {
path = map[string]string{}
for name := range val.Path.obj {
path[name] = r.PathValue(name)
}
}
var rewriteBody bool
if val.Body.Initialized() && val.Body.Kind() != KindFile {
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
w.WriteHeader(400)
_ = json.NewEncoder(w).Encode("failure decoding body: " + err.Error())
return
}
rewriteBody = true
}
var rewriteQuery bool
if val.Query.Initialized() {
query = r.URL.Query()
rewriteQuery = true
}
if err := router.Validate(val, query, body, path); err != nil {
w.WriteHeader(400)
_ = json.NewEncoder(w).Encode(err.Error())
return
}
// Validate can strip values that are not valid, so we rewrite them
// after validation is complete. Can't use defer as in other adapters
// because next.ServeHTTP calls the next handler and defer hasn't
// run yet.
if rewriteBody {
data, _ := json.Marshal(body)
_ = r.Body.Close()
r.Body = io.NopCloser(bytes.NewReader(data))
}
if rewriteQuery {
r.URL.RawQuery = query.Encode()
}
next.ServeHTTP(w, r)
})
}
}