-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathschema.go
108 lines (88 loc) · 2.35 KB
/
schema.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
package oas2
import (
"io"
"net/http"
"net/http/httptest"
"strings"
"github.com/RussellLuo/kun/pkg/httpcodec"
)
type Response struct {
StatusCode int
ContentType string
Body interface{}
}
type Schema interface {
SuccessResponse(name string, statusCode int, body interface{}) Response
FailureResponses(name string) []Response
}
type GetSuccessFunc func(body interface{}) interface{}
type GetFailuresFunc func(name string) map[error]interface{}
type ResponseSchema struct {
Codecs httpcodec.Codecs
GetSuccessFunc GetSuccessFunc
GetFailuresFunc GetFailuresFunc
}
func (rs *ResponseSchema) codecs() httpcodec.Codecs {
if rs.Codecs == nil {
rs.Codecs = httpcodec.NewDefaultCodecs(nil)
}
return rs.Codecs
}
func (rs *ResponseSchema) getSuccessFunc() GetSuccessFunc {
if rs.GetSuccessFunc == nil {
rs.GetSuccessFunc = func(body interface{}) interface{} {
return body
}
}
return rs.GetSuccessFunc
}
func (rs *ResponseSchema) SuccessResponse(name string, statusCode int, body interface{}) Response {
codec := rs.codecs().EncodeDecoder(name)
w := httptest.NewRecorder()
_ = codec.EncodeSuccessResponse(w, statusCode, body)
contentType := w.Result().Header.Get("Content-Type")
if statusCode == http.StatusNoContent || isMediaFile(contentType) {
body = nil
} else {
body = rs.getSuccessFunc()(body)
}
return Response{
StatusCode: statusCode,
ContentType: contentType,
Body: body,
}
}
func (rs *ResponseSchema) FailureResponses(name string) (resps []Response) {
if rs.GetFailuresFunc == nil {
return
}
codec := rs.codecs().EncodeDecoder(name)
for err, body := range rs.GetFailuresFunc(name) {
w := httptest.NewRecorder()
_ = codec.EncodeFailureResponse(w, err)
contentType := w.Result().Header.Get("Content-Type")
if body == nil {
body = decodePerContentType(contentType, w.Result().Body)
}
resps = append(resps, Response{
StatusCode: w.Result().StatusCode,
ContentType: contentType,
Body: body,
})
}
return
}
func decodePerContentType(contentType string, body io.ReadCloser) (out map[string]interface{}) {
switch {
case strings.HasPrefix(contentType, "application/json"):
_ = httpcodec.JSON{}.DecodeSuccessResponse(body, &out)
}
return
}
func Errors(errs ...error) map[error]interface{} {
m := make(map[error]interface{})
for _, err := range errs {
m[err] = nil
}
return m
}