145 lines
2.8 KiB
Go
145 lines
2.8 KiB
Go
|
package auroradns
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"io/ioutil"
|
||
|
"net/http"
|
||
|
"net/url"
|
||
|
)
|
||
|
|
||
|
const defaultBaseURL = "https://api.auroradns.eu"
|
||
|
|
||
|
const (
|
||
|
contentTypeHeader = "Content-Type"
|
||
|
contentTypeJSON = "application/json"
|
||
|
)
|
||
|
|
||
|
// ErrorResponse A representation of an API error message.
|
||
|
type ErrorResponse struct {
|
||
|
ErrorCode string `json:"error"`
|
||
|
Message string `json:"errormsg"`
|
||
|
}
|
||
|
|
||
|
func (e *ErrorResponse) Error() string {
|
||
|
return fmt.Sprintf("%s - %s", e.ErrorCode, e.Message)
|
||
|
}
|
||
|
|
||
|
// Option Type of a client option
|
||
|
type Option func(*Client) error
|
||
|
|
||
|
// Client The API client
|
||
|
type Client struct {
|
||
|
baseURL *url.URL
|
||
|
UserAgent string
|
||
|
httpClient *http.Client
|
||
|
}
|
||
|
|
||
|
// NewClient Creates a new client
|
||
|
func NewClient(httpClient *http.Client, opts ...Option) (*Client, error) {
|
||
|
if httpClient == nil {
|
||
|
httpClient = http.DefaultClient
|
||
|
}
|
||
|
|
||
|
baseURL, _ := url.Parse(defaultBaseURL)
|
||
|
|
||
|
client := &Client{
|
||
|
baseURL: baseURL,
|
||
|
httpClient: httpClient,
|
||
|
}
|
||
|
|
||
|
for _, opt := range opts {
|
||
|
err := opt(client)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return client, nil
|
||
|
}
|
||
|
|
||
|
func (c *Client) newRequest(method, resource string, body io.Reader) (*http.Request, error) {
|
||
|
u, err := c.baseURL.Parse(resource)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
req, err := http.NewRequest(method, u.String(), body)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
req.Header.Set(contentTypeHeader, contentTypeJSON)
|
||
|
|
||
|
if c.UserAgent != "" {
|
||
|
req.Header.Set("User-Agent", c.UserAgent)
|
||
|
}
|
||
|
|
||
|
return req, nil
|
||
|
}
|
||
|
|
||
|
func (c *Client) do(req *http.Request, v interface{}) (*http.Response, error) {
|
||
|
resp, err := c.httpClient.Do(req)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
defer func() { _ = resp.Body.Close() }()
|
||
|
|
||
|
if err = checkResponse(resp); err != nil {
|
||
|
return resp, err
|
||
|
}
|
||
|
|
||
|
if v == nil {
|
||
|
return resp, nil
|
||
|
}
|
||
|
|
||
|
raw, err := ioutil.ReadAll(resp.Body)
|
||
|
if err != nil {
|
||
|
return resp, fmt.Errorf("failed to read body: %v", err)
|
||
|
}
|
||
|
|
||
|
if err = json.Unmarshal(raw, v); err != nil {
|
||
|
return resp, fmt.Errorf("unmarshaling %T error: %v: %s", err, v, string(raw))
|
||
|
}
|
||
|
|
||
|
return resp, nil
|
||
|
}
|
||
|
|
||
|
func checkResponse(resp *http.Response) error {
|
||
|
if c := resp.StatusCode; 200 <= c && c <= 299 {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
data, err := ioutil.ReadAll(resp.Body)
|
||
|
if err == nil && data != nil {
|
||
|
errorResponse := new(ErrorResponse)
|
||
|
err = json.Unmarshal(data, errorResponse)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("unmarshaling ErrorResponse error: %v: %s", err.Error(), string(data))
|
||
|
}
|
||
|
|
||
|
return errorResponse
|
||
|
}
|
||
|
defer func() { _ = resp.Body.Close() }()
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// WithBaseURL Allows to define a custom base URL
|
||
|
func WithBaseURL(rawBaseURL string) func(*Client) error {
|
||
|
return func(client *Client) error {
|
||
|
if len(rawBaseURL) == 0 {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
baseURL, err := url.Parse(rawBaseURL)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
client.baseURL = baseURL
|
||
|
return nil
|
||
|
}
|
||
|
}
|