Skip to content

Commit

Permalink
feat(payments): replace http.Client with httpwrapper.Client in moneycorp
Browse files Browse the repository at this point in the history
  • Loading branch information
laouji committed Sep 17, 2024
1 parent 89d8059 commit b5e3a4a
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 122 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ type Config struct {
HttpErrorCheckerFn func(code int) error

Timeout time.Duration
Transport *http.Transport
Transport http.RoundTripper
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package client

import (
"context"
"encoding/json"
"fmt"
"net/http"
"strconv"

"github.com/formancehq/payments/internal/connectors/httpwrapper"
)

type accountsResponse struct {
Expand All @@ -20,7 +21,8 @@ type Account struct {
}

func (c *Client) GetAccounts(ctx context.Context, page int, pageSize int) ([]*Account, error) {
// TODO(polo): metrics
// TODO(polo, crimson): metrics
// metrics can also be embedded in wrapper
// f := connectors.ClientMetrics(ctx, "moneycorp", "list_accounts")
// now := time.Now()
// defer f(ctx, now)
Expand All @@ -31,6 +33,7 @@ func (c *Client) GetAccounts(ctx context.Context, page int, pageSize int) ([]*Ac
return nil, fmt.Errorf("failed to create accounts request: %w", err)
}

// TODO generic headers can be set in wrapper
req.Header.Set("Content-Type", "application/json")

q := req.URL.Query()
Expand All @@ -39,33 +42,15 @@ func (c *Client) GetAccounts(ctx context.Context, page int, pageSize int) ([]*Ac
q.Add("sortBy", "id.asc")
req.URL.RawQuery = q.Encode()

resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to get accounts: %w", err)
}

defer func() {
err = resp.Body.Close()
if err != nil {
// TODO(polo): log error
// c.logger.Error(err)
_ = err
}
}()

if resp.StatusCode == http.StatusNotFound {
return []*Account{}, nil
}

if resp.StatusCode != http.StatusOK {
accounts := accountsResponse{Accounts: make([]*Account, 0)}
var errRes moneycorpError
_, err = c.httpClient.Do(req, &accounts, &errRes)
switch err {
case nil:
return accounts.Accounts, nil
case httpwrapper.ErrStatusCodeUnexpected:
// TODO(polo): retryable errors
return nil, unmarshalError(resp.StatusCode, resp.Body).Error()
return nil, errRes.Error()
}

var accounts accountsResponse
if err := json.NewDecoder(resp.Body).Decode(&accounts); err != nil {
return nil, fmt.Errorf("failed to unmarshal accounts response body: %w", err)
}

return accounts.Accounts, nil
return nil, fmt.Errorf("failed to get accounts: %w", err)
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ func (t *apiTransport) login(ctx context.Context) error {

req.Header.Set("Content-Type", "application/json")

// TODO: default client doesn't have a timeout, so we should be careful about using it here
resp, err := http.DefaultClient.Do(req)
if err != nil {
return fmt.Errorf("failed to login: %w", err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"encoding/json"
"fmt"
"net/http"

"github.com/formancehq/payments/internal/connectors/httpwrapper"
)

type balancesResponse struct {
Expand Down Expand Up @@ -36,32 +38,16 @@ func (c *Client) GetAccountBalances(ctx context.Context, accountID string) ([]*B
}
req.Header.Set("Content-Type", "application/json")

resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to get account balances: %w", err)
}
balances := balancesResponse{Balances: make([]*Balance, 0)}
var errRes moneycorpError

defer func() {
err = resp.Body.Close()
if err != nil {
// TODO(polo): log error
// c.logger.Error(err)
_ = err
}
}()

if resp.StatusCode == http.StatusNotFound {
return []*Balance{}, nil
_, err = c.httpClient.Do(req, &balances, &errRes)
switch err {
case nil:
return balances.Balances, nil
case httpwrapper.ErrStatusCodeUnexpected:
// TODO(polo): retryable errors
return nil, errRes.Error()
}

if resp.StatusCode != http.StatusOK {
return nil, unmarshalError(resp.StatusCode, resp.Body).Error()
}

var balances balancesResponse
if err := json.NewDecoder(resp.Body).Decode(&balances); err != nil {
return nil, fmt.Errorf("failed to unmarshal balances response body: %w", err)
}

return balances.Balances, nil
return nil, fmt.Errorf("failed to get account balances: %w", err)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,41 @@ package client
import (
"net/http"
"strings"
"time"

"github.com/formancehq/payments/internal/connectors/httpwrapper"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)

type Client struct {
httpClient *http.Client
httpClient httpwrapper.Client
endpoint string
}

func newHTTPClient(clientID, apiKey, endpoint string) *http.Client {
return &http.Client{
Timeout: 10 * time.Second,
func New(clientID, apiKey, endpoint string) (*Client, error) {
config := &httpwrapper.Config{
Transport: &apiTransport{
clientID: clientID,
apiKey: apiKey,
endpoint: endpoint,
underlying: otelhttp.NewTransport(http.DefaultTransport),
},
}
}
HttpErrorCheckerFn: func(statusCode int) error {
if statusCode == http.StatusNotFound {
return nil
}
if statusCode >= http.StatusBadRequest {
return httpwrapper.ErrStatusCodeUnexpected
}
return nil

func New(clientID, apiKey, endpoint string) (*Client, error) {
},
}
endpoint = strings.TrimSuffix(endpoint, "/")

httpClient, err := httpwrapper.NewClient(config)
c := &Client{
httpClient: newHTTPClient(clientID, apiKey, endpoint),
httpClient: httpClient,
endpoint: endpoint,
}

return c, nil
return c, err
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package client

import (
"context"
"encoding/json"
"fmt"
"net/http"
"strconv"

"github.com/formancehq/payments/internal/connectors/httpwrapper"
)

type recipientsResponse struct {
Expand Down Expand Up @@ -41,33 +42,15 @@ func (c *Client) GetRecipients(ctx context.Context, accountID string, page int,
q.Add("sortBy", "createdAt.asc")
req.URL.RawQuery = q.Encode()

resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to get accounts: %w", err)
}

defer func() {
err = resp.Body.Close()
if err != nil {
// TODO(polo): log error
// c.logger.Error(err)
_ = err
}
}()

if resp.StatusCode == http.StatusNotFound {
return []*Recipient{}, nil
}

if resp.StatusCode != http.StatusOK {
recipients := recipientsResponse{Recipients: make([]*Recipient, 0)}
var errRes moneycorpError
_, err = c.httpClient.Do(req, &recipients, &errRes)
switch err {
case nil:
return recipients.Recipients, nil
case httpwrapper.ErrStatusCodeUnexpected:
// TODO(polo): retryable errors
return nil, unmarshalError(resp.StatusCode, resp.Body).Error()
return nil, errRes.Error()
}

var recipients recipientsResponse
if err := json.NewDecoder(resp.Body).Decode(&recipients); err != nil {
return nil, fmt.Errorf("failed to unmarshal recipients response body: %w", err)
}

return recipients.Recipients, nil
return nil, fmt.Errorf("failed to get recipients %w", err)
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"net/http"
"strconv"
"time"

"github.com/formancehq/payments/internal/connectors/httpwrapper"
)

type transactionsResponse struct {
Expand Down Expand Up @@ -84,33 +86,15 @@ func (c *Client) GetTransactions(ctx context.Context, accountID string, page, pa
q.Add("sortBy", "createdAt.asc")
req.URL.RawQuery = q.Encode()

resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to get transactions: %w", err)
}

defer func() {
err = resp.Body.Close()
if err != nil {
// TODO(polo): log error
// c.logger.Error(err)
_ = err
}
}()

if resp.StatusCode == http.StatusNotFound {
return []*Transaction{}, nil
}

if resp.StatusCode != http.StatusOK {
transactions := transactionsResponse{Transactions: make([]*Transaction, 0)}
var errRes moneycorpError
_, err = c.httpClient.Do(req, &transactions, &errRes)
switch err {
case nil:
return transactions.Transactions, nil
case httpwrapper.ErrStatusCodeUnexpected:
// TODO(polo): retryable errors
return nil, unmarshalError(resp.StatusCode, resp.Body).Error()
return nil, errRes.Error()
}

var transactions transactionsResponse
if err := json.NewDecoder(resp.Body).Decode(&transactions); err != nil {
return nil, fmt.Errorf("failed to unmarshal transactions response body: %w", err)
}

return transactions.Transactions, nil
return nil, fmt.Errorf("failed to get transactions %w", err)
}

0 comments on commit b5e3a4a

Please sign in to comment.