diff --git a/.gitignore b/.gitignore index 1f6e21e..d70a5fb 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,27 @@ *.a *.so +# Folders +_obj + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof + # IDE's files .idea +*.iml # Project ignores diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..e2efa03 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,7 @@ +language: go +go: + - "1.8" + - "1.9" +before_install: + - go get -v github.com/google/go-querystring/query +script: go test -v ./... diff --git a/README.md b/README.md index edd96f6..432c043 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +[![Build Status](https://img.shields.io/travis/retailcrm/api-client-go/master.svg?style=flat-square)](https://travis-ci.org/retailcrm/api-client-go) +[![Downloads](https://img.shields.io/github/downloads/dt/retailcrm/api-client-go.svg?style=flat-square)](https://packagist.org/packages/retailcrm/api-client-go/stats) + # retailCRM API Go client Go client for [retailCRM API](http://www.retailcrm.pro/docs/Developers/ApiVersion5). diff --git a/client.go b/client.go new file mode 100644 index 0000000..1b37527 --- /dev/null +++ b/client.go @@ -0,0 +1,112 @@ +package retailcrm + +import ( + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "strings" + "time" +) + +const ( + ApiPrefix = "/api/v5" +) + +type Client struct { + Url string + apiKey string + httpClient *http.Client +} + +type ErrorResponse struct { + ErrorMsg string `json:"errorMsg,omitempty"` + Errors map[string]string `json:"errors,omitempty"` +} + +func New(url string, apiKey string) *Client { + return &Client{ + url, + apiKey, + &http.Client{Timeout: 20 * time.Second}, + } +} + +func (r *Client) GetRequest(urlWithParameters string) ([]byte, int, error) { + var res []byte + + req, err := http.NewRequest("GET", fmt.Sprintf("%s%s%s", r.Url, ApiPrefix, urlWithParameters), nil) + if err != nil { + return res, 0, err + } + + req.Header.Set("X-API-KEY", r.apiKey) + + resp, err := r.httpClient.Do(req) + if err != nil { + return res, 0, err + } + + if resp.StatusCode >= http.StatusInternalServerError { + return res, resp.StatusCode, errors.New(fmt.Sprintf("HTTP request error. Status code: %d.\n", resp.StatusCode)) + } + + res, err = buildRawResponse(resp) + if err != nil { + return res, 0, err + } + + return res, resp.StatusCode, nil +} + +func (r *Client) PostRequest(url string, postParams url.Values) ([]byte, int, error) { + var res []byte + + req, err := http.NewRequest( + "POST", + fmt.Sprintf("%s%s%s", r.Url, ApiPrefix, url), + strings.NewReader(postParams.Encode()), + ) + if err != nil { + return res, 0, err + } + + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + req.Header.Set("X-API-KEY", r.apiKey) + + resp, err := r.httpClient.Do(req) + if err != nil { + return res, 0, err + } + + if resp.StatusCode >= http.StatusInternalServerError { + return res, resp.StatusCode, errors.New(fmt.Sprintf("HTTP request error. Status code: %d.\n", resp.StatusCode)) + } + + res, err = buildRawResponse(resp) + if err != nil { + return res, 0, err + } + + return res, resp.StatusCode, nil +} + +func buildRawResponse(resp *http.Response) ([]byte, error) { + defer resp.Body.Close() + + res, err := ioutil.ReadAll(resp.Body) + if err != nil { + return res, err + } + + return res, nil +} + +func (r *Client) ErrorResponse(data []byte) (*ErrorResponse, error) { + var resp ErrorResponse + err := json.Unmarshal(data, &resp) + + return &resp, err +} diff --git a/client_test.go b/client_test.go new file mode 100644 index 0000000..80110ae --- /dev/null +++ b/client_test.go @@ -0,0 +1,45 @@ +package retailcrm + +import ( + "net/http" + "net/url" + "testing" +) + +const ( + TestUrl = "https://demo.retailcrm.ru" + TestApiKey = "111" + WrongApiKeyMsg = "Wrong \"apiKey\" value." +) + +func client() *Client { + return New(TestUrl, TestApiKey) +} + +func TestGetRequest(t *testing.T) { + c := client() + + data, status, _ := c.GetRequest("/store/products") + if status != http.StatusForbidden { + t.Fail() + } + + resp, _ := c.ErrorResponse(data) + if resp.ErrorMsg != WrongApiKeyMsg { + t.Fail() + } +} + +func TestPostRequest(t *testing.T) { + c := client() + + data, status, _ := c.PostRequest("/orders/create", url.Values{}) + if status != http.StatusForbidden { + t.Fail() + } + + resp, _ := c.ErrorResponse(data) + if resp.ErrorMsg != WrongApiKeyMsg { + t.Fail() + } +}