diff --git a/services/external/weni/sentenx/client.go b/services/external/weni/sentenx/client.go new file mode 100644 index 000000000..ab7257b91 --- /dev/null +++ b/services/external/weni/sentenx/client.go @@ -0,0 +1,90 @@ +package sentenx + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + + "github.com/nyaruka/gocommon/httpx" + "github.com/nyaruka/gocommon/jsonx" + "github.com/pkg/errors" +) + +const BaseURL = "https://sentenx.weni.ai" + +type SearchRequest struct { + Search string `json:"search,omitempty"` + Filter struct { + CatalogID string `json:"catalog_id,omitempty"` + } `json:"filter,omitempty"` + Threshold float64 `json:"threshold,omitempty"` +} + +type SearchResponse struct { + Products []Product `json:"products,omitempty"` +} + +type Product struct { + ProductRetailerID string `json:"product_retailer_id,omitempty"` +} + +type ErrorResponse struct { + Detail []struct { + Msg string `json:"msg,omitempty"` + } `json:"detail,omitempty"` +} + +type Client struct { + httpClient *http.Client + httpRetries *httpx.RetryConfig + baseURL string +} + +func NewClient(httpClient *http.Client, httpRetries *httpx.RetryConfig, baseURL string) *Client { + return &Client{httpClient, httpRetries, baseURL} +} + +func (c *Client) Request(method, url string, body, response interface{}) (*httpx.Trace, error) { + b, err := json.Marshal(body) + if err != nil { + return nil, err + } + + data := strings.NewReader(string(b)) + req, err := httpx.NewRequest(method, url, data, nil) + if err != nil { + return nil, err + } + + trace, err := httpx.DoTrace(c.httpClient, req, c.httpRetries, nil, -1) + if err != nil { + return trace, err + } + + if trace.Response.StatusCode >= 400 { + var errorResponse []ErrorResponse + err = jsonx.Unmarshal(trace.ResponseBody, &errorResponse) + if err != nil { + return trace, err + } + return trace, errors.New(fmt.Sprint(errorResponse)) + } + + if response != nil { + err := json.Unmarshal(trace.ResponseBody, response) + return trace, errors.Wrap(err, "couldn't unmarshal response body") + } + return trace, nil +} + +func (c *Client) Search(data *SearchRequest) (*SearchResponse, *httpx.Trace, error) { + requestURL := c.baseURL + "/search" + response := &SearchResponse{} + + trace, err := c.Request("GET", requestURL, data, response) + if err != nil { + return nil, trace, err + } + return response, trace, nil +} diff --git a/services/external/weni/sentenx/client_test.go b/services/external/weni/sentenx/client_test.go new file mode 100644 index 000000000..869621815 --- /dev/null +++ b/services/external/weni/sentenx/client_test.go @@ -0,0 +1,47 @@ +package sentenx_test + +import ( + "net/http" + "testing" + + "github.com/nyaruka/gocommon/httpx" + "github.com/nyaruka/mailroom/services/external/weni/sentenx" + "github.com/stretchr/testify/assert" +) + +const ( + baseURL = "https://sentenx.weni.ai" +) + +func TestRequest(t *testing.T) { + client := sentenx.NewClient(http.DefaultClient, nil, baseURL) + + _, err := client.Request("POST", "", func() {}, nil) + assert.Error(t, err) + + _, err = client.Request("{[:INVALID:]}", "", nil, nil) + assert.Error(t, err) + + defer httpx.SetRequestor(httpx.DefaultRequestor) + httpx.SetRequestor(httpx.NewMockRequestor(map[string][]httpx.MockResponse{ + baseURL: { + httpx.NewMockResponse(400, nil, `[]`), + httpx.NewMockResponse(200, nil, `{}`), + httpx.NewMockResponse(400, nil, `{ + "detail": [ + { "msg": "dummy error message"} + ] + }`), + }, + })) + + _, err = client.Request("GET", baseURL, nil, nil) + assert.Error(t, err) + + _, err = client.Request("GET", baseURL, nil, nil) + assert.Nil(t, err) + + response := new(interface{}) + _, err = client.Request("GET", baseURL, nil, response) + assert.Error(t, err) +}