This repository has been archived by the owner on Jun 1, 2023. It is now read-only.
forked from sendgrid/rest
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rest.go
140 lines (120 loc) · 3.45 KB
/
rest.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 rest allows for quick and easy access any REST or REST-like API.
package rest
import (
"bytes"
"io/ioutil"
"net/http"
"net/url"
)
// Method contains the supported HTTP verbs.
type Method string
// Supported HTTP verbs.
const (
Get Method = "GET"
Post Method = "POST"
Put Method = "PUT"
Patch Method = "PATCH"
Delete Method = "DELETE"
)
// Request holds the request to an API Call.
type Request struct {
Method Method
BaseURL string // e.g. https://api.sendgrid.com
Headers map[string]string
QueryParams map[string]string
Body []byte
}
// RestError is a struct for an error handling.
type RestError struct {
Response *Response
}
// Error is the implementation of the error interface.
func (e *RestError) Error() string {
return e.Response.Body
}
// DefaultClient is used if no custom HTTP client is defined
var DefaultClient = &Client{HTTPClient: http.DefaultClient}
// Client allows modification of client headers, redirect policy
// and other settings
// See https://golang.org/pkg/net/http
type Client struct {
HTTPClient *http.Client
}
// Response holds the response from an API call.
type Response struct {
StatusCode int // e.g. 200
Body string // e.g. {"result: success"}
Headers map[string][]string // e.g. map[X-Ratelimit-Limit:[600]]
}
// AddQueryParameters adds query paramaters to the URL.
func AddQueryParameters(baseURL string, queryParams map[string]string) string {
baseURL += "?"
params := url.Values{}
for key, value := range queryParams {
params.Add(key, value)
}
return baseURL + params.Encode()
}
// BuildRequestObject creates the HTTP request object.
func BuildRequestObject(request Request) (*http.Request, error) {
// Add any query parameters to the URL.
if len(request.QueryParams) != 0 {
request.BaseURL = AddQueryParameters(request.BaseURL, request.QueryParams)
}
req, err := http.NewRequest(string(request.Method), request.BaseURL, bytes.NewBuffer(request.Body))
for key, value := range request.Headers {
req.Header.Set(key, value)
}
_, exists := req.Header["Content-Type"]
if len(request.Body) > 0 && !exists {
req.Header.Set("Content-Type", "application/json")
}
return req, err
}
// MakeRequest makes the API call.
func MakeRequest(req *http.Request) (*http.Response, error) {
return DefaultClient.HTTPClient.Do(req)
}
// BuildResponse builds the response struct.
func BuildResponse(res *http.Response) (*Response, error) {
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
defer res.Body.Close()
response := Response{
StatusCode: res.StatusCode,
Body: string(body),
Headers: res.Header,
}
return &response, nil
}
// API is the main interface to the API.
func API(request Request) (*Response, error) {
return DefaultClient.API(request)
}
// The following functions enable the ability to define a
// custom HTTP Client
// MakeRequest makes the API call.
func (c *Client) MakeRequest(req *http.Request) (*http.Response, error) {
return c.HTTPClient.Do(req)
}
// API is the main interface to the API.
func (c *Client) API(request Request) (*Response, error) {
// Build the HTTP request object.
req, err := BuildRequestObject(request)
if err != nil {
return nil, err
}
// Build the HTTP client and make the request.
res, err := c.MakeRequest(req)
if err != nil {
return nil, err
}
// Build Response object.
response, err := BuildResponse(res)
if err != nil {
return nil, err
}
return response, nil
}