115 lines
3.7 KiB
Go
115 lines
3.7 KiB
Go
package itglue
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/url"
|
|
)
|
|
|
|
//TBD: Implement
|
|
type Links struct{}
|
|
|
|
type Metadata struct {
|
|
CurrentPage int `json:"current-page"`
|
|
NextPage interface{} `json:"next-page"`
|
|
PrevPage interface{} `json:"prev-page"`
|
|
TotalPages int `json:"total-pages"`
|
|
TotalCount int `json:"total-count"`
|
|
Filters struct {
|
|
} `json:"filters"`
|
|
}
|
|
|
|
//ITGAPI contains the ITG API URL for North America, as well as the API key.
|
|
//Think of it as an instance of the API client
|
|
type ITGAPI struct {
|
|
Site string //Full URL ITG API
|
|
APIKey string //API Key
|
|
}
|
|
|
|
type Request struct {
|
|
ITG *ITGAPI
|
|
RestAction string
|
|
Method string //GET, POST, DELETE, etc
|
|
Body []byte //In a GET request, this is an instance of the struct that the expected json data is to be unmarshaled into
|
|
URLValues url.Values //Parameters sent to ITG for filtering by conditions that utilize strings
|
|
RawURLValues string //URL values must be a string. Raw URL values allow an int to be used, for instance in a filter
|
|
Page int
|
|
PageSize int
|
|
}
|
|
|
|
//NewITGAPI expects the API key to be passed to it
|
|
//Returns a pointer to an ITGAPI struct
|
|
func NewITGAPI(apiKey string) *ITGAPI {
|
|
return &ITGAPI{Site: "https://api.itglue.com", APIKey: apiKey}
|
|
}
|
|
|
|
//NewRequest is a function which takes the mandatory fields to perform a request to the CW API and returns a pointer to a Request struct
|
|
func (itg *ITGAPI) NewRequest(restAction, method string, body []byte) *Request {
|
|
req := Request{ITG: itg, RestAction: restAction, Method: method, Body: body}
|
|
req.URLValues = url.Values{}
|
|
return &req
|
|
}
|
|
|
|
//Do is a method of the Request struct which uses the data contained within the Request instance to perform an HTTP request to ConnectWise
|
|
func (req *Request) Do() error {
|
|
itgurl, err := req.ITG.BuildURL(req.RestAction)
|
|
if err != nil {
|
|
return fmt.Errorf("could not build url %s: %s", req.RestAction, err)
|
|
}
|
|
|
|
//If pagination parameters are not being specified, then don't include them in the URL - not all endpoints will accept page and pagesize, they will 400 - bad request
|
|
if req.Page == 0 || req.PageSize == 0 {
|
|
itgurl.RawQuery = fmt.Sprintf("%s%s", req.URLValues.Encode(), req.RawURLValues)
|
|
} else {
|
|
itgurl.RawQuery = fmt.Sprintf("%s%s&page[number]=%d&page[size]=%d", req.URLValues.Encode(), req.RawURLValues, req.Page, req.PageSize)
|
|
}
|
|
|
|
client := &http.Client{}
|
|
jsonBuffer := bytes.NewReader(req.Body)
|
|
httpreq, err := http.NewRequest(req.Method, itgurl.String(), jsonBuffer)
|
|
if err != nil {
|
|
return fmt.Errorf("could not construct http request: %s", err)
|
|
}
|
|
httpreq.Header.Set("Content-Type", "application/vnd.api+json")
|
|
httpreq.Header.Set("x-api-key", req.ITG.APIKey)
|
|
httpreq.Header.Set("cache-control", "no-cache")
|
|
|
|
resp, err := client.Do(httpreq)
|
|
if err != nil {
|
|
return fmt.Errorf("could not perform http %s request: %s", req.Method, err)
|
|
}
|
|
req.Body, err = getHTTPResponseBody(resp)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get http response body: %s", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getHTTPResponseBody(resp *http.Response) ([]byte, error) {
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, fmt.Errorf("ITG returned HTTP status code %s\n%s", resp.Status, resp.Body)
|
|
}
|
|
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not read http response body: %s", err)
|
|
}
|
|
|
|
return body, nil
|
|
}
|
|
|
|
//BuildURL expects a restaction to be passed to it
|
|
//Returns the full request URL containing the ITG API domain prepended to the rest action
|
|
func (itg *ITGAPI) BuildURL(restAction string) (*url.URL, error) {
|
|
var itgurl *url.URL
|
|
itgurl, err := url.Parse(itg.Site)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not parse url %s: %s", itg.Site, err)
|
|
}
|
|
itgurl.Path += restAction
|
|
return itgurl, nil
|
|
}
|