-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathrequest.go
110 lines (94 loc) · 2.72 KB
/
request.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
package katapult
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
)
// Request represents a HTTP request to the Katapult API, it is essentially
// similar to http.Request, but stripped down to the bare essentials, with some
// Katapult-specific attributes added.
type Request struct {
// Method is the HTTP method to perform when making the request.
Method string
// URL is the request URL to perform against Katapult's API. Generally the
// only fields you need to set are Path and RawQuery, as it will be merged
// with the Client's BaseURL value through its ResolveReference() method.
URL *url.URL
// NoAuth instructs Client not to send Authorization header containing the
// APIKey. This is useful for public endpoints which do not require/use
// authentication.
NoAuth bool
// Header holds request-specific HTTP headers. Client.Do() will set a number
// of essential headers itself which cannot be customized through
// Request.Headers.
Header http.Header
// ContentType allows sending a custom request body of any mimetype. If set
// Body must be a io.Reader. If not set Body must be a object which can be
// serialized with json.Marshal(). Content-Type header is only sent when
// Body is not nil.
ContentType string
// Body can be any object which can be marshaled to JSON through
// json.Marshal() when ContentType is not set. If ContentType is set, Body
// must be a io.Reader, or nil.
//
// No validation is performed between Method and Body, making it possible to
// send a body with a method that does not allow it.
Body interface{}
}
type RequestOption = func(r *Request)
// RequestSetHeader sets a header on the outgoing request. This replaces any
// headers that are currently specified with that key.
func RequestSetHeader(key, value string) RequestOption {
return func(r *Request) {
r.Header.Set(key, value)
}
}
func NewRequest(
method string,
u *url.URL,
body interface{},
opts ...RequestOption,
) *Request {
r := &Request{
Method: method,
URL: u,
Body: body,
Header: map[string][]string{},
}
// Apply options to created Client
for _, opt := range opts {
opt(r)
}
return r
}
func (r *Request) bodyContent() (string, io.Reader, error) {
if r.Body == nil {
return "", nil, nil
}
contentType := r.ContentType
var body io.Reader
if contentType == "" {
contentType = "application/json"
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
enc.SetEscapeHTML(false)
err := enc.Encode(r.Body)
if err != nil {
return "", nil, err
}
body = &buf
} else {
var ok bool
body, ok = r.Body.(io.Reader)
if !ok {
return "", nil, fmt.Errorf(
"%w: Body must be a io.Reader when ContentType is set",
ErrRequest,
)
}
}
return contentType, body, nil
}