Added error handling

This commit is contained in:
Steven Polley 2018-07-22 01:41:33 -06:00
parent 3440d00924
commit cff418c0ff
3 changed files with 105 additions and 31 deletions

3
.gitignore vendored
View File

@ -1 +1,2 @@
example/main.go example/main.go
.vscode/tasks.json

View File

@ -4,15 +4,18 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"log"
"net/http" "net/http"
"net/url" "net/url"
) )
func check(err error) { type Metadata struct {
if err != nil { CurrentPage int `json:"current-page"`
log.Fatal(err) 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. //ITGAPI contains the ITG API URL for North America, as well as the API key.
@ -28,43 +31,48 @@ func NewITGAPI(apiKey string) *ITGAPI {
return &ITGAPI{Site: "https://api.itglue.com", APIKey: apiKey} return &ITGAPI{Site: "https://api.itglue.com", APIKey: apiKey}
} }
func getHTTPResponseBody(resp *http.Response) []byte { func getHTTPResponseBody(resp *http.Response) ([]byte, error) {
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("ITG returned HTTP status code %s\n%s", resp.Status, resp.Body)
out := fmt.Sprintf("ITG returned HTTP status code %s\n%s", resp.Status, resp.Body)
log.Fatal(out)
return make([]byte, 0) //TBD: Don't hack
} }
body, err := ioutil.ReadAll(resp.Body) body, err := ioutil.ReadAll(resp.Body)
check(err) if err != nil {
return nil, fmt.Errorf("could not read http response body: %s", err)
}
return body return body, nil
} }
//BuildURL expects a restaction to be passed to it //BuildURL expects a restaction to be passed to it
//Returns the full request URL containing the ITG API domain prepended to the rest action //Returns the full request URL containing the ITG API domain prepended to the rest action
func (itg *ITGAPI) BuildURL(restAction string) *url.URL { func (itg *ITGAPI) BuildURL(restAction string) (*url.URL, error) {
var itgurl *url.URL var itgurl *url.URL
itgurl, err := url.Parse(itg.Site) itgurl, err := url.Parse(itg.Site)
check(err) if err != nil {
return nil, fmt.Errorf("could not parse url %s: %s", itg.Site, err)
}
itgurl.Path += restAction itgurl.Path += restAction
return itgurl return itgurl, nil
} }
//GetRequest allows a custom GET request to the API to be made. //GetRequest allows a custom GET request to the API to be made.
//Also used internally by this package by the binding functions //Also used internally by this package by the binding functions
//Expects URL to be passed //Expects URL to be passed
//Returns the response body as a byte slice //Returns the response body as a byte slice
func (itg *ITGAPI) GetRequest(itgurl *url.URL) []byte { func (itg *ITGAPI) GetRequest(itgurl *url.URL) ([]byte, error) {
client := &http.Client{} client := &http.Client{}
req, err := http.NewRequest("GET", itgurl.String(), nil) req, err := http.NewRequest("GET", itgurl.String(), nil)
check(err) if err != nil {
return nil, fmt.Errorf("could not create http request: %s", err)
}
req.Header.Set("Content-Type", "application/vnd.api+json") req.Header.Set("Content-Type", "application/vnd.api+json")
req.Header.Set("x-api-key", itg.APIKey) req.Header.Set("x-api-key", itg.APIKey)
req.Header.Set("cache-control", "no-cache") req.Header.Set("cache-control", "no-cache")
response, err := client.Do(req) response, err := client.Do(req)
check(err) if err != nil {
return nil, fmt.Errorf("http request failed: %s", err)
}
defer response.Body.Close() defer response.Body.Close()
return getHTTPResponseBody(response) return getHTTPResponseBody(response)
@ -74,15 +82,19 @@ func (itg *ITGAPI) GetRequest(itgurl *url.URL) []byte {
//Also used internally by this package by the binding functions //Also used internally by this package by the binding functions
//Expects a URL and a body to be passed //Expects a URL and a body to be passed
//Returns the response body as a byte slice //Returns the response body as a byte slice
func (itg *ITGAPI) PostRequest(itgurl *url.URL, body io.Reader) []byte { func (itg *ITGAPI) PostRequest(itgurl *url.URL, body io.Reader) ([]byte, error) {
client := &http.Client{} client := &http.Client{}
req, err := http.NewRequest("POST", itgurl.String(), body) req, err := http.NewRequest("POST", itgurl.String(), body)
check(err) if err != nil {
return nil, fmt.Errorf("could not create http request: %s", err)
}
req.Header.Set("Content-Type", "application/vnd.api+json") req.Header.Set("Content-Type", "application/vnd.api+json")
req.Header.Set("x-api-key", itg.APIKey) req.Header.Set("x-api-key", itg.APIKey)
req.Header.Set("cache-control", "no-cache") req.Header.Set("cache-control", "no-cache")
response, err := client.Do(req) response, err := client.Do(req)
check(err) if err != nil {
return nil, fmt.Errorf("http request failed: %s", err)
}
defer response.Body.Close() defer response.Body.Close()
return getHTTPResponseBody(response) return getHTTPResponseBody(response)
@ -93,15 +105,19 @@ func (itg *ITGAPI) PostRequest(itgurl *url.URL, body io.Reader) []byte {
//Also used internally by this package by the binding functions //Also used internally by this package by the binding functions
//Expects a URL and a body to be passed //Expects a URL and a body to be passed
//Returns the response body as a byte slice //Returns the response body as a byte slice
func (itg *ITGAPI) PatchRequest(itgurl *url.URL, body io.Reader) []byte { func (itg *ITGAPI) PatchRequest(itgurl *url.URL, body io.Reader) ([]byte, error) {
client := &http.Client{} client := &http.Client{}
req, err := http.NewRequest("PATCH", itgurl.String(), body) req, err := http.NewRequest("PATCH", itgurl.String(), body)
check(err) if err != nil {
return nil, fmt.Errorf("could not create http request: %s", err)
}
req.Header.Set("Content-Type", "application/vnd.api+json") req.Header.Set("Content-Type", "application/vnd.api+json")
req.Header.Set("x-api-key", itg.APIKey) req.Header.Set("x-api-key", itg.APIKey)
req.Header.Set("cache-control", "no-cache") req.Header.Set("cache-control", "no-cache")
response, err := client.Do(req) response, err := client.Do(req)
check(err) if err != nil {
return nil, fmt.Errorf("http request failed: %s", err)
}
defer response.Body.Close() defer response.Body.Close()
return getHTTPResponseBody(response) return getHTTPResponseBody(response)

View File

@ -4,8 +4,32 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/url" "net/url"
"time"
) )
type OrganizationTypeData struct {
ID string `json:"id"`
Type string `json:"type"`
Attributes struct {
Name string `json:"name"`
CreatedAt time.Time `json:"created-at"`
UpdatedAt time.Time `json:"updated-at"`
Synced bool `json:"synced"`
} `json:"attributes"`
Meta 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"`
} `json:"meta"`
Links struct {
} `json:"links"`
}
//OrganizationInternalData contains the schema of an Organization in IT Glue without the "data" wrapper. //OrganizationInternalData contains the schema of an Organization in IT Glue without the "data" wrapper.
//This allows us to reuse the schema when data is either a JSON object or an array, depending on what results are returned //This allows us to reuse the schema when data is either a JSON object or an array, depending on what results are returned
type OrganizationInternalData struct { type OrganizationInternalData struct {
@ -36,13 +60,40 @@ type OrganizationList struct {
Data []struct{ OrganizationInternalData } `json:"data"` Data []struct{ OrganizationInternalData } `json:"data"`
} }
///organization_types
func (itg *ITGAPI) GetOrganizationTypes() error {
itgurl, err := itg.BuildURL("/organization_types")
if err != nil {
return fmt.Errorf("could not build URL: %s", err)
}
body, err := itg.GetRequest(itgurl)
if err != nil {
return fmt.Errorf("request failed: %s", err)
}
fmt.Println(string(body))
/*organization := &Organization{}
err := json.Unmarshal(body, organization)
if err != nil {
return nil, fmt.Errorf("could not get organization: %s", err)
}
*/
return nil
}
//GetOrganizationByID expects an ITG organization ID //GetOrganizationByID expects an ITG organization ID
//Returns a pointer to an Organization struct //Returns a pointer to an Organization struct
func (itg *ITGAPI) GetOrganizationByID(organizationID int) (*Organization, error) { func (itg *ITGAPI) GetOrganizationByID(organizationID int) (*Organization, error) {
itgurl := itg.BuildURL(fmt.Sprintf("/organizations/%d", organizationID)) itgurl, err := itg.BuildURL(fmt.Sprintf("/organizations/%d", organizationID))
body := itg.GetRequest(itgurl) if err != nil {
return nil, fmt.Errorf("could not build URL: %s", err)
}
body, err := itg.GetRequest(itgurl)
if err != nil {
return nil, fmt.Errorf("request failed: %s", err)
}
organization := &Organization{} organization := &Organization{}
err := json.Unmarshal(body, organization) err = json.Unmarshal(body, organization)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not get organization: %s", err) return nil, fmt.Errorf("could not get organization: %s", err)
} }
@ -51,13 +102,19 @@ func (itg *ITGAPI) GetOrganizationByID(organizationID int) (*Organization, error
//GetOrganizationByName expects an exact matching organization name and returns an OrganizationList //GetOrganizationByName expects an exact matching organization name and returns an OrganizationList
func (itg *ITGAPI) GetOrganizationByName(organizationName string) (*OrganizationList, error) { func (itg *ITGAPI) GetOrganizationByName(organizationName string) (*OrganizationList, error) {
itgurl := itg.BuildURL("/organizations") itgurl, err := itg.BuildURL("/organizations")
if err != nil {
return nil, fmt.Errorf("could not build URL: %s", err)
}
params := url.Values{} params := url.Values{}
params.Add("filter[name]", organizationName) params.Add("filter[name]", organizationName)
itgurl.RawQuery = params.Encode() itgurl.RawQuery = params.Encode()
body := itg.GetRequest(itgurl) body, err := itg.GetRequest(itgurl)
if err != nil {
return nil, fmt.Errorf("request failed: %s", err)
}
organization := &OrganizationList{} organization := &OrganizationList{}
err := json.Unmarshal(body, organization) err = json.Unmarshal(body, organization)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not get organization: %s", err) return nil, fmt.Errorf("could not get organization: %s", err)
} }