2018-06-20 19:24:47 +00:00
package connectwise
import (
2018-07-07 00:26:11 +00:00
"bytes"
2018-07-08 21:16:59 +00:00
"encoding/json"
2018-06-20 19:24:47 +00:00
"fmt"
"io/ioutil"
"net/http"
2018-06-20 20:23:49 +00:00
"net/url"
2018-06-20 19:24:47 +00:00
)
2018-07-06 22:21:00 +00:00
//Request is a struct which holds all information that is collected in order to make a request
type Request struct {
2018-07-07 00:29:53 +00:00
CW * Site
2018-07-06 22:21:00 +00:00
RestAction string
2018-07-08 15:50:05 +00:00
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
2018-07-08 17:21:07 +00:00
URLValues url . Values //Parameters sent to CW for filtering by conditions that utilize strings
Page int
PageSize int
2018-07-06 22:21:00 +00:00
}
2018-07-10 02:48:02 +00:00
//Patch is a struct which holds the required fields to make a PATCH request
type Patch struct {
Op string ` json:"op" `
Path string ` json:"path" `
Value string ` json:"value" `
}
2018-07-07 00:26:11 +00:00
//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
2018-07-08 21:16:59 +00:00
func ( cw * Site ) NewRequest ( restAction , method string , body [ ] byte ) * Request {
2018-07-06 22:21:00 +00:00
req := Request { CW : cw , RestAction : restAction , Method : method , Body : body }
2018-07-08 15:50:05 +00:00
req . URLValues = url . Values { }
2018-07-06 22:21:00 +00:00
return & req
}
2018-07-08 21:16:59 +00:00
//NewPaginationRequest is a method which takes in the mandatory fields to paginate
//TBD - finish this
func ( cw * Site ) NewPaginationRequest ( restAction , method string , body [ ] byte , pageSize , pageNumber int ) ( * [ ] Company , error ) {
req := cw . NewRequest ( "/company/companies" , "GET" , nil )
req . Page = pageNumber
req . PageSize = pageSize
err := req . Do ( )
if err != nil {
return nil , fmt . Errorf ( "request failed for %s: %s" , req . RestAction , err )
}
co := & [ ] Company { }
err = json . Unmarshal ( req . Body , co )
if err != nil {
return nil , fmt . Errorf ( "failed to unmarshal body into struct: %s" , err )
}
return co , nil
}
2018-07-07 00:26:11 +00:00
//Do is a method of the Request struct which uses the data contained within the Request instance to perform an HTTP request to ConnectWise
2018-07-06 22:21:00 +00:00
func ( req * Request ) Do ( ) error {
cwurl , err := req . CW . BuildURL ( req . RestAction )
if err != nil {
return fmt . Errorf ( "could not build url %s: %s" , req . RestAction , err )
}
2018-07-08 17:21:07 +00:00
//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 {
cwurl . RawQuery = req . URLValues . Encode ( )
} else {
cwurl . RawQuery = fmt . Sprintf ( "%s&page=%d&pageSize=%d" , req . URLValues . Encode ( ) , req . Page , req . PageSize )
}
2018-07-06 22:21:00 +00:00
2018-07-07 00:26:11 +00:00
client := & http . Client { }
jsonBuffer := bytes . NewReader ( req . Body )
httpreq , err := http . NewRequest ( req . Method , cwurl . String ( ) , jsonBuffer )
2018-07-06 22:21:00 +00:00
if err != nil {
2018-07-07 00:26:11 +00:00
return fmt . Errorf ( "could not construct http request: %s" , err )
}
httpreq . Header . Set ( "Authorization" , req . CW . Auth )
httpreq . Header . Set ( "Content-Type" , "application/json" )
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 )
2018-07-06 22:21:00 +00:00
}
return nil
}
2018-06-29 01:35:34 +00:00
//BuildURL will take a REST action such as "/companies/company/5" and then append the CW site to it and return a pointer to a url.URL
2018-07-07 00:29:53 +00:00
func ( cw * Site ) BuildURL ( restAction string ) ( * url . URL , error ) {
2018-06-29 01:35:34 +00:00
var cwurl * url . URL
cwurl , err := url . Parse ( cw . Site )
2018-07-06 03:20:52 +00:00
if err != nil {
2018-07-06 14:37:53 +00:00
return nil , fmt . Errorf ( "could not %s as url: %s" , cw . Site , err )
2018-07-06 03:20:52 +00:00
}
2018-06-29 01:35:34 +00:00
cwurl . Path += restAction
2018-06-23 00:47:39 +00:00
2018-07-06 03:20:52 +00:00
return cwurl , nil
2018-06-23 00:47:39 +00:00
}
2018-06-20 19:24:47 +00:00
//Checks for HTTP errors, and if all looks good, returns the body of the HTTP response as a byte slice
2018-06-20 21:59:12 +00:00
//TBD: Needs to accept 201 and 204 (returned for Create and Delete operations)
2018-07-06 03:20:52 +00:00
func getHTTPResponseBody ( resp * http . Response ) ( [ ] byte , error ) {
2018-06-22 20:14:21 +00:00
if ( resp . StatusCode != http . StatusOK ) && ( resp . StatusCode != http . StatusCreated ) && ( resp . StatusCode != http . StatusNoContent ) {
2018-07-06 14:37:53 +00:00
return nil , fmt . Errorf ( "cw api returned unexpected http status %d - %s" , resp . StatusCode , resp . Status )
2018-06-20 19:24:47 +00:00
}
2018-07-06 03:20:52 +00:00
defer resp . Body . Close ( )
2018-06-29 01:35:34 +00:00
body , err := ioutil . ReadAll ( resp . Body )
2018-07-06 03:20:52 +00:00
if err != nil {
return nil , fmt . Errorf ( "could not read response body of request" )
}
2018-06-29 01:35:34 +00:00
2018-07-06 03:20:52 +00:00
return body , nil
2018-06-20 19:24:47 +00:00
}