2018-06-29 22:53:14 +00:00
package itglue
import (
2018-07-23 00:51:25 +00:00
"bytes"
2018-06-29 22:53:14 +00:00
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
)
2018-07-22 08:24:52 +00:00
//TBD: Implement
type Links struct { }
2018-07-22 07:41:33 +00:00
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" `
2018-06-29 22:53:14 +00:00
}
//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
}
2018-07-23 00:51:25 +00:00
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
Page int
PageSize int
}
//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 = req . URLValues . Encode ( )
} else {
itgurl . RawQuery = fmt . Sprintf ( "%s&page[number]=%d&page[size]=%d" , req . URLValues . Encode ( ) , 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
}
2018-06-29 22:53:14 +00:00
//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 }
}
2018-07-22 07:41:33 +00:00
func getHTTPResponseBody ( resp * http . Response ) ( [ ] byte , error ) {
2018-06-29 22:53:14 +00:00
if resp . StatusCode != http . StatusOK {
2018-07-22 07:41:33 +00:00
return nil , fmt . Errorf ( "ITG returned HTTP status code %s\n%s" , resp . Status , resp . Body )
2018-06-29 22:53:14 +00:00
}
body , err := ioutil . ReadAll ( resp . Body )
2018-07-22 07:41:33 +00:00
if err != nil {
return nil , fmt . Errorf ( "could not read http response body: %s" , err )
}
2018-06-29 22:53:14 +00:00
2018-07-22 07:41:33 +00:00
return body , nil
2018-06-29 22:53:14 +00:00
}
//BuildURL expects a restaction to be passed to it
//Returns the full request URL containing the ITG API domain prepended to the rest action
2018-07-22 07:41:33 +00:00
func ( itg * ITGAPI ) BuildURL ( restAction string ) ( * url . URL , error ) {
2018-06-29 22:56:22 +00:00
var itgurl * url . URL
itgurl , err := url . Parse ( itg . Site )
2018-07-22 07:41:33 +00:00
if err != nil {
return nil , fmt . Errorf ( "could not parse url %s: %s" , itg . Site , err )
}
2018-06-29 22:56:22 +00:00
itgurl . Path += restAction
2018-07-22 07:41:33 +00:00
return itgurl , nil
2018-06-29 22:53:14 +00:00
}
//GetRequest allows a custom GET request to the API to be made.
//Also used internally by this package by the binding functions
//Expects URL to be passed
//Returns the response body as a byte slice
2018-07-22 07:41:33 +00:00
func ( itg * ITGAPI ) GetRequest ( itgurl * url . URL ) ( [ ] byte , error ) {
2018-06-29 22:53:14 +00:00
client := & http . Client { }
2018-06-29 22:56:22 +00:00
req , err := http . NewRequest ( "GET" , itgurl . String ( ) , nil )
2018-07-22 07:41:33 +00:00
if err != nil {
return nil , fmt . Errorf ( "could not create http request: %s" , err )
}
2018-06-29 22:53:14 +00:00
req . Header . Set ( "Content-Type" , "application/vnd.api+json" )
req . Header . Set ( "x-api-key" , itg . APIKey )
req . Header . Set ( "cache-control" , "no-cache" )
response , err := client . Do ( req )
2018-07-22 07:41:33 +00:00
if err != nil {
return nil , fmt . Errorf ( "http request failed: %s" , err )
}
2018-06-29 22:53:14 +00:00
defer response . Body . Close ( )
return getHTTPResponseBody ( response )
}
//PostRequest allows a custom POST request tot he API to be made
//Also used internally by this package by the binding functions
//Expects a URL and a body to be passed
//Returns the response body as a byte slice
2018-07-22 07:41:33 +00:00
func ( itg * ITGAPI ) PostRequest ( itgurl * url . URL , body io . Reader ) ( [ ] byte , error ) {
2018-06-29 22:53:14 +00:00
client := & http . Client { }
2018-06-29 22:56:22 +00:00
req , err := http . NewRequest ( "POST" , itgurl . String ( ) , body )
2018-07-22 07:41:33 +00:00
if err != nil {
return nil , fmt . Errorf ( "could not create http request: %s" , err )
}
2018-06-29 22:53:14 +00:00
req . Header . Set ( "Content-Type" , "application/vnd.api+json" )
req . Header . Set ( "x-api-key" , itg . APIKey )
req . Header . Set ( "cache-control" , "no-cache" )
response , err := client . Do ( req )
2018-07-22 07:41:33 +00:00
if err != nil {
return nil , fmt . Errorf ( "http request failed: %s" , err )
}
2018-06-29 22:53:14 +00:00
defer response . Body . Close ( )
return getHTTPResponseBody ( response )
}
//PatchRequest allows a custom PATCH request tot he API to be made
//Also used internally by this package by the binding functions
//Expects a URL and a body to be passed
//Returns the response body as a byte slice
2018-07-22 07:41:33 +00:00
func ( itg * ITGAPI ) PatchRequest ( itgurl * url . URL , body io . Reader ) ( [ ] byte , error ) {
2018-06-29 22:53:14 +00:00
client := & http . Client { }
2018-06-29 22:56:22 +00:00
req , err := http . NewRequest ( "PATCH" , itgurl . String ( ) , body )
2018-07-22 07:41:33 +00:00
if err != nil {
return nil , fmt . Errorf ( "could not create http request: %s" , err )
}
2018-06-29 22:53:14 +00:00
req . Header . Set ( "Content-Type" , "application/vnd.api+json" )
req . Header . Set ( "x-api-key" , itg . APIKey )
req . Header . Set ( "cache-control" , "no-cache" )
response , err := client . Do ( req )
2018-07-22 07:41:33 +00:00
if err != nil {
return nil , fmt . Errorf ( "http request failed: %s" , err )
}
2018-06-29 22:53:14 +00:00
defer response . Body . Close ( )
return getHTTPResponseBody ( response )
}