151 lines
3.5 KiB
Go
151 lines
3.5 KiB
Go
package rest
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"github.com/Jeffail/gabs"
|
|
)
|
|
|
|
// 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.service.com
|
|
Headers map[string]string
|
|
QueryParams map[string]string
|
|
Body []byte
|
|
}
|
|
|
|
// Response holds the response from an API call.
|
|
type Response struct {
|
|
StatusCode int // e.g. 200
|
|
Headers http.Header // e.g. map[X-Rate-Limit:[600]]
|
|
Body string // e.g. {"result: success"}
|
|
JSON *gabs.Container
|
|
}
|
|
|
|
// ParseJSON parses the response body to JSON container.
|
|
func (r *Response) ParseJSON() error {
|
|
if strings.Contains(r.Headers.Get("Content-Type"), "application/json") {
|
|
json, err := gabs.ParseJSON([]byte(r.Body))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
r.JSON = json
|
|
return nil
|
|
}
|
|
|
|
return errors.New("response body is not JSON")
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// 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(r *Request) (*Response, error) {
|
|
// Build the HTTP request object.
|
|
req, err := BuildRequestObject(r)
|
|
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
|
|
}
|
|
|
|
// AddQueryParameters adds query parameters 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(r *Request) (*http.Request, error) {
|
|
// Add any query parameters to the URL.
|
|
if len(r.QueryParams) != 0 {
|
|
r.BaseURL = AddQueryParameters(r.BaseURL, r.QueryParams)
|
|
}
|
|
req, err := http.NewRequest(string(r.Method), r.BaseURL, bytes.NewBuffer(r.Body))
|
|
for key, value := range r.Headers {
|
|
req.Header.Set(key, value)
|
|
}
|
|
_, exists := req.Header["Content-Type"]
|
|
if len(r.Body) > 0 && !exists {
|
|
req.Header.Set("Content-Type", "application/json")
|
|
}
|
|
return req, err
|
|
}
|
|
|
|
// BuildResponse builds the response struct.
|
|
func BuildResponse(r *http.Response) (*Response, error) {
|
|
body, err := ioutil.ReadAll(r.Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer r.Body.Close()
|
|
|
|
response := Response{
|
|
StatusCode: r.StatusCode,
|
|
Body: string(body),
|
|
Headers: r.Header,
|
|
}
|
|
|
|
return &response, nil
|
|
}
|
|
|
|
// MakeRequest makes the API call.
|
|
func MakeRequest(r *http.Request) (*http.Response, error) {
|
|
return DefaultClient.HTTPClient.Do(r)
|
|
}
|
|
|
|
// API is the main interface to the API.
|
|
func API(request *Request) (*Response, error) {
|
|
return DefaultClient.API(request)
|
|
}
|