-
Notifications
You must be signed in to change notification settings - Fork 0
/
response.go
143 lines (119 loc) · 2.89 KB
/
response.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
141
142
143
package mockhttp
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
)
type Response interface {
Status() int
Body() string
}
type RawResponse struct {
status int
body string
}
func NewRawResponse() *RawResponse {
return &RawResponse{}
}
func (r *RawResponse) Status() int {
return r.status
}
func (r *RawResponse) Body() string {
return r.body
}
func (r *RawResponse) WithStatus(status int) *RawResponse {
r.status = status
return r
}
func (r *RawResponse) WithBody(body string) *RawResponse {
r.body = body
return r
}
type JSONResponse[T any] struct {
status int
body string
Val *T
validationFunc func(expected, result T) error
}
func NewJSONResponse[T any]() *JSONResponse[T] {
return &JSONResponse[T]{}
}
func (r *JSONResponse[T]) Status() int {
return r.status
}
func (r *JSONResponse[T]) Body() string {
return r.body
}
func (r *JSONResponse[T]) WithStatus(status int) *JSONResponse[T] {
r.status = status
return r
}
func (r *JSONResponse[T]) WithSuccess(val *T) *JSONResponse[T] {
r.status = 200
r.Val = val
return r
}
func (r *JSONResponse[T]) WithFailure(status int, val *T) *JSONResponse[T] {
r.status = status
r.Val = val
return r
}
func (r *JSONResponse[T]) WithValidationFunc(f func(expected, result T) error) *JSONResponse[T] {
r.validationFunc = f
return r
}
// ToResponse takes a httpResponse and maps it to a JSONResponse object
// It saves the status and saves the body
func ToResponse(res *http.Response) (*RawResponse, error) {
defer res.Body.Close()
data, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
return &RawResponse{
status: res.StatusCode,
body: string(data),
}, nil
}
// ToJSONResponse takes a httpResponse and maps it to a JSONResponse object
// It saves the status and parses the body into the expected type
// It will return an error if the http.Response is not a 200
func ToJSONResponse[T any](res *http.Response) (*JSONResponse[T], error) {
defer res.Body.Close()
data, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
ret := &JSONResponse[T]{
status: res.StatusCode,
body: string(data),
}
if len(ret.body) == 0 {
return nil, errors.New("expected a payload in the response body, but got an empty string")
}
var t T
ret.Val = &t
err = json.Unmarshal(data, ret.Val)
if err != nil {
return nil, err
}
return ret, nil
}
// Validate performs validation for two JSON Responses
func (expected *JSONResponse[T]) Validate(result *JSONResponse[T]) error {
if expected == nil {
return errors.New("receiver expected should not be nil")
}
if result == nil {
return errors.New("parameter result should not be nil")
}
if expected.status != result.status {
return fmt.Errorf("expected status %d, but got %d", expected.status, result.status)
}
if expected.validationFunc != nil {
return expected.validationFunc(*expected.Val, *result.Val)
}
return nil
}