Skip to content

Commit

Permalink
add integration with generic httpclient
Browse files Browse the repository at this point in the history
  • Loading branch information
edmarSoaress committed Feb 7, 2024
2 parents eec206b + a04fea5 commit 7c220ea
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 198 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
# sdk-go
Mercado Pago's official Go SDK.
Mercado Pago's official Go SDK.

This library is a work in progress.
137 changes: 137 additions & 0 deletions pkg/internal/httpclient/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package httpclient

import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"runtime"
"strings"

"github.com/google/uuid"
"github.com/mercadopago/sdk-go/pkg/config"
)

const (
currentSDKVersion string = "x.x.x"
productID string = "abc"
accept string = "application/json"
contentType string = "application/json; charset=UTF-8"

headerProductID = "X-Product-Id"
headerAccept = "Accept"
headerContentType = "Content-Type"
headerUserAgent = "User-Agent"
headerTrackingID = "X-Tracking-Id"
headerRequestID = "X-Request-Id"
headerAuthorization = "Authorization"
headerIdempotency = "X-Idempotency-Key"

headerCorporationID = "X-Corporation-Id"
headerIntegratorID = "X-Integrator-Id"
headerPlatformID = "X-Platform-Id"
)

var (
userAgent = fmt.Sprintf("MercadoPago Go SDK/%s", currentSDKVersion)
trackingID = fmt.Sprintf("platform:%s,type:SDK%s,so;", runtime.Version(), currentSDKVersion)
)

// Get makes requests with the GET method
// Will return the struct specified in Generics
func Get[T any](ctx context.Context, cfg *config.Config, path string) (*T, error) {
req, err := makeRequest(ctx, cfg, http.MethodGet, path, nil)
if err != nil {
return nil, err
}

return send[T](cfg.Requester, req)
}

// Post makes requests with the POST method
// Will return the struct specified in Generics
func Post[T any](ctx context.Context, cfg *config.Config, path string, body any) (*T, error) {
req, err := makeRequest(ctx, cfg, http.MethodPost, path, body)
if err != nil {
return nil, err
}

return send[T](cfg.Requester, req)
}

// Put makes requests with the PUT method
// Will return the struct specified in Generics
func Put[T any](ctx context.Context, cfg *config.Config, path string, body any) (*T, error) {
req, err := makeRequest(ctx, cfg, http.MethodPut, path, body)
if err != nil {
return nil, err
}

return send[T](cfg.Requester, req)
}

// Delete makes requests with the DELETE method
// Will return the struct specified in Generics
func Delete[T any](ctx context.Context, cfg *config.Config, path string, body any) (*T, error) {
req, err := makeRequest(ctx, cfg, http.MethodDelete, path, body)
if err != nil {
return nil, err
}

return send[T](cfg.Requester, req)
}

func makeRequest(ctx context.Context, cfg *config.Config, method, path string, body any) (*http.Request, error) {
req, err := buildHTTPRequest(ctx, method, path, body)
if err != nil {
return nil, fmt.Errorf("error creating request: %w", err)
}

makeHeaders(req, cfg)

return req, nil
}

func makeHeaders(req *http.Request, cfg *config.Config) {
req.Header.Set(headerProductID, productID)
req.Header.Set(headerAccept, accept)
req.Header.Set(headerContentType, contentType)
req.Header.Set(headerUserAgent, userAgent)
req.Header.Set(headerTrackingID, trackingID)
req.Header.Set(headerAuthorization, "Bearer "+cfg.AccessToken)
req.Header.Set(headerIdempotency, uuid.New().String())
req.Header.Set(headerRequestID, uuid.New().String())

if cfg.CorporationID != "" {
req.Header.Set(headerCorporationID, cfg.CorporationID)
}
if cfg.IntegratorID != "" {
req.Header.Set(headerIntegratorID, cfg.IntegratorID)
}
if cfg.PlatformID != "" {
req.Header.Set(headerPlatformID, cfg.PlatformID)
}
}

func buildHTTPRequest(ctx context.Context, method, url string, body any) (*http.Request, error) {
b, err := buildBody(body)
if err != nil {
return nil, err
}

return http.NewRequestWithContext(ctx, method, url, b)
}

func buildBody(body any) (io.Reader, error) {
if body == nil {
return nil, nil
}

b, err := json.Marshal(&body)
if err != nil {
return nil, fmt.Errorf("error marshaling request body: %w", err)
}

return strings.NewReader(string(b)), nil
}
63 changes: 11 additions & 52 deletions pkg/internal/httpclient/gateway.go
Original file line number Diff line number Diff line change
@@ -1,65 +1,15 @@
package httpclient

import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"runtime"

"github.com/google/uuid"
"github.com/mercadopago/sdk-go/pkg/config"
"github.com/mercadopago/sdk-go/pkg/internal/requester"
)

const (
currentSDKVersion string = "x.x.x"
productID string = "abc"
accept string = "application/json"
contentType string = "application/json; charset=UTF-8"

productIDHeader = "X-Product-Id"
acceptHeader = "Accept"
contentTypeHeader = "Content-Type"
userAgentHeader = "User-Agent"
trackingIDHeader = "X-Tracking-Id"
authorizationHeader = "Authorization"
idempotencyHeader = "X-Idempotency-Key"

corporationIDHeader = "X-Corporation-Id"
integratorIDHeader = "X-Integrator-Id"
platformIDHeader = "X-Platform-Id"
)

var (
userAgent = fmt.Sprintf("MercadoPago Go SDK/%s", currentSDKVersion)
trackingID = fmt.Sprintf("platform:%s,type:SDK%s,so;", runtime.Version(), currentSDKVersion)
)

// Send wraps needed options before send api call.
func Send(ctx context.Context, cfg *config.Config, req *http.Request) ([]byte, error) {
req.Header.Set(productIDHeader, productID)
req.Header.Set(acceptHeader, accept)
req.Header.Set(contentTypeHeader, contentType)
req.Header.Set(userAgentHeader, userAgent)
req.Header.Set(trackingIDHeader, trackingID)
req.Header.Set(authorizationHeader, "Bearer "+cfg.AccessToken)
req.Header.Set(idempotencyHeader, uuid.New().String())

if cfg.CorporationID != "" {
req.Header.Set(corporationIDHeader, cfg.CorporationID)
}
if cfg.IntegratorID != "" {
req.Header.Set(integratorIDHeader, cfg.IntegratorID)
}
if cfg.PlatformID != "" {
req.Header.Set(platformIDHeader, cfg.PlatformID)
}

return send(ctx, cfg.Requester, req)
}

func send(_ context.Context, requester requester.Requester, req *http.Request) ([]byte, error) {
func send[T any](requester requester.Requester, req *http.Request) (*T, error) {
res, err := requester.Do(req)
if err != nil {
return nil, fmt.Errorf("transport level error: %w", err)
Expand All @@ -84,5 +34,14 @@ func send(_ context.Context, requester requester.Requester, req *http.Request) (
}
}

return makeResponse[T](response)
}

func makeResponse[T any](b []byte) (*T, error) {
var response *T
if err := json.Unmarshal(b, &response); err != nil {
return nil, err
}

return response, nil
}
Loading

0 comments on commit 7c220ea

Please sign in to comment.