14 const apiBaseURL = "https://app.statuscake.com/API"
16 type responseBody struct {
20 func (r *responseBody) Close() error {
24 // Auth wraps the authorisation headers required for each request
30 func (a *Auth) validate() error {
31 e := make(ValidationError)
34 e["Username"] = "is required"
38 e["Apikey"] = "is required"
48 type httpClient interface {
49 Do(*http.Request) (*http.Response, error)
52 type apiClient interface {
53 get(string, url.Values) (*http.Response, error)
54 delete(string, url.Values) (*http.Response, error)
55 put(string, url.Values) (*http.Response, error)
58 // Client is the http client that wraps the remote API.
66 // New returns a new Client
67 func New(auth Auth) (*Client, error) {
68 if err := auth.validate(); err != nil {
74 username: auth.Username,
79 func (c *Client) newRequest(method string, path string, v url.Values, body io.Reader) (*http.Request, error) {
80 url := fmt.Sprintf("%s%s", apiBaseURL, path)
82 url = fmt.Sprintf("%s?%s", url, v.Encode())
85 r, err := http.NewRequest(method, url, body)
90 r.Header.Set("Username", c.username)
91 r.Header.Set("API", c.apiKey)
96 func (c *Client) doRequest(r *http.Request) (*http.Response, error) {
97 resp, err := c.c.Do(r)
101 defer resp.Body.Close()
103 if resp.StatusCode < 200 || resp.StatusCode > 299 {
104 return nil, &httpError{
106 statusCode: resp.StatusCode,
110 var aer autheticationErrorResponse
112 // We read and save the response body so that if we don't have error messages
113 // we can set it again for future usage
114 b, err := ioutil.ReadAll(resp.Body)
119 err = json.Unmarshal(b, &aer)
120 if err == nil && aer.ErrNo == 0 && aer.Error != "" {
121 return nil, &AuthenticationError{
127 resp.Body = &responseBody{
128 Reader: bytes.NewReader(b),
134 func (c *Client) get(path string, v url.Values) (*http.Response, error) {
135 r, err := c.newRequest("GET", path, v, nil)
140 return c.doRequest(r)
143 func (c *Client) put(path string, v url.Values) (*http.Response, error) {
144 r, err := c.newRequest("PUT", path, nil, strings.NewReader(v.Encode()))
145 r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
151 return c.doRequest(r)
154 func (c *Client) delete(path string, v url.Values) (*http.Response, error) {
155 r, err := c.newRequest("DELETE", path, v, nil)
160 return c.doRequest(r)
163 // Tests returns a client that implements the `Tests` API.
164 func (c *Client) Tests() Tests {
165 if c.testsClient == nil {
166 c.testsClient = newTests(c)