diff --git a/client.go b/client.go index 53f96d9..0fa055b 100644 --- a/client.go +++ b/client.go @@ -3,23 +3,21 @@ package monobank // TODO: add HTTP retry import ( - "context" - "encoding/json" - "io" "net/http" "net/url" - "time" "github.com/pkg/errors" + "github.com/vtopc/go-rest" + "github.com/vtopc/go-rest/defaults" + "github.com/vtopc/go-rest/interceptors" ) const ( - baseURL = "https://api.monobank.ua" - defaultTimeout = 30 * time.Second + baseURL = "https://api.monobank.ua" ) type Client struct { - httpClient *http.Client + restClient *rest.Client auth Authorizer baseURL string // TODO: switch to url.URL } @@ -29,14 +27,14 @@ type Client struct { // NewClient - returns public monobank Client func NewClient(client *http.Client) Client { if client == nil { - // defaults - client = &http.Client{ - Timeout: defaultTimeout, - } + client = defaults.NewHTTPClient() } + _ = interceptors.SetReqContentType(client, "application/json") + c := rest.NewClient(client) + return Client{ - httpClient: client, + restClient: c, auth: NewPublicAuthorizer(), baseURL: baseURL, } @@ -54,9 +52,7 @@ func (c *Client) withAuth(auth Authorizer) { // do does request. // Stores JSON response in the value pointed to by v. // TODO: make expectedStatusCode a slice: -func (c Client) do(ctx context.Context, req *http.Request, v interface{}, expectedStatusCode int) error { - // TODO: check that `v` is a pointer or nil - +func (c Client) do(req *http.Request, v interface{}, expectedStatusCode int) error { if req == nil { return errors.New("empty request") } @@ -67,59 +63,16 @@ func (c Client) do(ctx context.Context, req *http.Request, v interface{}, expect return errors.Wrap(err, "failed to build URL") } - req = req.WithContext(ctx) - if c.auth != nil { // TODO: return an error if not err = c.auth.SetAuth(req) if err != nil { - return NewReqError(req, errors.Wrap(err, "SetAuth")) + return errors.Wrap(err, "SetAuth") } } - if req.Body != nil { - req.Header.Set("Content-Type", "application/json") - } - - err = func() error { - resp, e := c.httpClient.Do(req) - if e != nil { - return e - } - - defer resp.Body.Close() - - var body []byte - if v != nil { - body, e = io.ReadAll(resp.Body) - if e != nil { - return errors.Wrap(e, "couldn't read the body") - } - } - - // TODO: switch to "for" for multi-status: - if resp.StatusCode == expectedStatusCode { - if v == nil { - // nothing to unmarshal - return nil - } - - e = json.Unmarshal(body, v) - if e == nil { - return nil - } - - return errors.Wrap(e, "failed to unmarshal the response body") - } - - // otherwise, non expected status code: - return &APIError{ - ResponseStatusCode: resp.StatusCode, - ExpectedStatusCodes: []int{expectedStatusCode}, - Err: errors.New(string(body)), - } - }() + err = c.restClient.Do(req, v, expectedStatusCode) if err != nil { - return NewReqError(req, err) + return err } return nil diff --git a/client_test.go b/client_test.go index a1e7481..f337461 100644 --- a/client_test.go +++ b/client_test.go @@ -1,7 +1,6 @@ package monobank import ( - "context" "net/http" "net/http/httptest" "strings" @@ -9,6 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/vtopc/go-rest" ) func TestClient_do(t *testing.T) { @@ -45,14 +45,14 @@ func TestClient_do(t *testing.T) { c := Client{ baseURL: server.URL, - httpClient: server.Client(), + restClient: rest.NewClient(server.Client()), } req, err := http.NewRequest(tc.method, tc.urlPostfix, http.NoBody) require.NoError(t, err) // test: - err = c.do(context.Background(), req, &tc.v, tc.expectedStatusCode) + err = c.do(req, &tc.v, tc.expectedStatusCode) require.NoError(t, err) assert.Equal(t, tc.want, tc.v) }) diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..69cb760 --- /dev/null +++ b/codecov.yml @@ -0,0 +1 @@ +comment: false diff --git a/common.go b/common.go index eaf8657..2c9bfdb 100644 --- a/common.go +++ b/common.go @@ -32,13 +32,13 @@ func newCommonClient(client *http.Client) commonClient { func (c commonClient) ClientInfo(ctx context.Context) (*ClientInfo, error) { const urlPath = "/personal/client-info" - req, err := http.NewRequest(http.MethodGet, urlPath, http.NoBody) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, urlPath, http.NoBody) if err != nil { return nil, errors.Wrap(err, "failed to create request") } var v ClientInfo - err = c.do(ctx, req, &v, http.StatusOK) + err = c.do(req, &v, http.StatusOK) return &v, err } @@ -50,13 +50,13 @@ func (c commonClient) Transactions(ctx context.Context, accountID string, from, const urlPath = "/personal/statement" uri := fmt.Sprintf("%s/%s/%d/%d", urlPath, accountID, from.Unix(), to.Unix()) - req, err := http.NewRequest(http.MethodGet, uri, http.NoBody) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, http.NoBody) if err != nil { return nil, errors.Wrap(err, "failed to create request") } var v Transactions - err = c.do(ctx, req, &v, http.StatusOK) + err = c.do(req, &v, http.StatusOK) return v, err } @@ -68,10 +68,10 @@ func (c commonClient) setWebHook(ctx context.Context, uri, urlPath string) error return errors.Wrap(err, "failed to marshal") } - req, err := http.NewRequest(http.MethodPost, urlPath, &buf) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, urlPath, &buf) if err != nil { return errors.Wrap(err, "failed to create request") } - return c.do(ctx, req, nil, http.StatusOK) + return c.do(req, nil, http.StatusOK) } diff --git a/corporate.go b/corporate.go index a6863de..c7fe1a8 100644 --- a/corporate.go +++ b/corporate.go @@ -53,7 +53,7 @@ func NewCorporateClient(client *http.Client, authMaker CorpAuthMakerAPI) (Corpor // Auth initializes access. func (c CorporateClient) Auth(ctx context.Context, callbackURL string, permissions ...string) (*TokenRequest, error) { - req, err := http.NewRequest(http.MethodPost, urlPathAuth, http.NoBody) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, urlPathAuth, http.NoBody) if err != nil { return nil, errors.Wrap(err, "failed to create request") } @@ -63,20 +63,20 @@ func (c CorporateClient) Auth(ctx context.Context, callbackURL string, permissio authClient := c.withAuth(c.authMaker.NewPermissions(permissions...)) var v TokenRequest - err = authClient.commonClient.do(ctx, req, &v, http.StatusOK) + err = authClient.commonClient.do(req, &v, http.StatusOK) return &v, err } func (c CorporateClient) CheckAuth(ctx context.Context, requestID string) error { - req, err := http.NewRequest(http.MethodGet, urlPathAuth, http.NoBody) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, urlPathAuth, http.NoBody) if err != nil { return errors.Wrap(err, "failed to create request") } authClient := c.withAuth(c.authMaker.New(requestID)) - return authClient.do(ctx, req, nil, http.StatusOK) + return authClient.do(req, nil, http.StatusOK) } // SetWebHook sets webhook for corporate API. diff --git a/go.mod b/go.mod index ece3982..bc86ee2 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.16 require ( github.com/decred/dcrd/dcrec/secp256k1/v2 v2.0.0 github.com/pkg/errors v0.9.1 - github.com/stretchr/testify v1.4.0 + github.com/stretchr/testify v1.7.0 github.com/vtopc/epoch v1.0.0 + github.com/vtopc/go-rest v0.2.0 ) diff --git a/go.sum b/go.sum index aeeee11..f9cf421 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,3 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -8,18 +7,21 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v2 v2.0.0 h1:3GIJYXQDAKpLEFriGFN8SbSffak10UXHGdIcFaMPykY= github.com/decred/dcrd/dcrec/secp256k1/v2 v2.0.0/go.mod h1:3s92l0paYkZoIHuj4X93Teg/HB7eGM9x/zokGw+u4mY= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/vtopc/epoch v1.0.0 h1:C9lSFt9DC/J0YlW3Eheq4vBBi0pk2hjC8XFb3indWlw= github.com/vtopc/epoch v1.0.0/go.mod h1:/jzmj/iiCMyAiIk3T6RGPUpMpPSjUJDG2Yu7FzfEt8U= +github.com/vtopc/go-rest v0.2.0 h1:ZdNndlwzk1NjWbKf8yHGo8Bn1DRolWAtuPbIBvAVN5k= +github.com/vtopc/go-rest v0.2.0/go.mod h1:t7XPUz57Z+U66vsVIjEm89Uw/NZf486JVAFhq6+mZps= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/public.go b/public.go index f16208f..cb7b17b 100644 --- a/public.go +++ b/public.go @@ -15,13 +15,13 @@ type PublicAPI interface { func (c Client) Currency(ctx context.Context) (Currencies, error) { const urlPath = "/bank/currency" - req, err := http.NewRequest(http.MethodGet, urlPath, http.NoBody) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, urlPath, http.NoBody) if err != nil { return nil, errors.Wrap(err, "failed to create request") } var v Currencies - err = c.do(ctx, req, &v, http.StatusOK) + err = c.do(req, &v, http.StatusOK) return v, err }