/
rest_client.go
128 lines (104 loc) · 3 KB
/
rest_client.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
package api
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"github.com/cli/go-gh/pkg/api"
)
// Implements api.RESTClient interface.
type restClient struct {
client http.Client
host string
}
func NewRESTClient(host string, opts *api.ClientOptions) api.RESTClient {
return restClient{
client: NewHTTPClient(opts),
host: host,
}
}
func (c restClient) RequestWithContext(ctx context.Context, method string, path string, body io.Reader) (*http.Response, error) {
url := restURL(c.host, path)
req, err := http.NewRequestWithContext(ctx, method, url, body)
if err != nil {
return nil, err
}
resp, err := c.client.Do(req)
if err != nil {
return nil, err
}
success := resp.StatusCode >= 200 && resp.StatusCode < 300
if !success {
defer resp.Body.Close()
return nil, api.HandleHTTPError(resp)
}
return resp, err
}
func (c restClient) Request(method string, path string, body io.Reader) (*http.Response, error) {
return c.RequestWithContext(context.Background(), method, path, body)
}
func (c restClient) DoWithContext(ctx context.Context, method string, path string, body io.Reader, response interface{}) error {
url := restURL(c.host, path)
req, err := http.NewRequestWithContext(ctx, method, url, body)
if err != nil {
return err
}
resp, err := c.client.Do(req)
if err != nil {
return err
}
success := resp.StatusCode >= 200 && resp.StatusCode < 300
if !success {
defer resp.Body.Close()
return api.HandleHTTPError(resp)
}
if resp.StatusCode == http.StatusNoContent {
return nil
}
defer resp.Body.Close()
b, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
err = json.Unmarshal(b, &response)
if err != nil {
return err
}
return nil
}
func (c restClient) Do(method string, path string, body io.Reader, response interface{}) error {
return c.DoWithContext(context.Background(), method, path, body, response)
}
func (c restClient) Delete(path string, resp interface{}) error {
return c.Do(http.MethodDelete, path, nil, resp)
}
func (c restClient) Get(path string, resp interface{}) error {
return c.Do(http.MethodGet, path, nil, resp)
}
func (c restClient) Patch(path string, body io.Reader, resp interface{}) error {
return c.Do(http.MethodPatch, path, body, resp)
}
func (c restClient) Post(path string, body io.Reader, resp interface{}) error {
return c.Do(http.MethodPost, path, body, resp)
}
func (c restClient) Put(path string, body io.Reader, resp interface{}) error {
return c.Do(http.MethodPut, path, body, resp)
}
func restURL(hostname string, pathOrURL string) string {
if strings.HasPrefix(pathOrURL, "https://") || strings.HasPrefix(pathOrURL, "http://") {
return pathOrURL
}
return restPrefix(hostname) + pathOrURL
}
func restPrefix(hostname string) string {
hostname = normalizeHostname(hostname)
if isEnterprise(hostname) {
return fmt.Sprintf("https://%s/api/v3/", hostname)
}
if strings.EqualFold(hostname, localhost) {
return fmt.Sprintf("http://api.%s/", hostname)
}
return fmt.Sprintf("https://api.%s/", hostname)
}