S SmartDocs
Serie: Go go 69 líneas · Actualizado 2026-04-18

client.go

Go/payment-gateway-challenge/internal/bank/client.go

// Package bank implements the HTTP client that talks to the acquiring-bank
// simulator (Mountebank). The gateway translates merchant-facing JSON into the
// simulator's expected body shape and interprets HTTP status + JSON body.
package bank

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

	"payment-gateway-challenge/internal/validation"
)

// Client calls the external bank simulator over HTTP.
type Client struct {
	baseURL    string
	httpClient *http.Client
}

// NewClient builds a bank client. baseURL should be the full payments URL,
// e.g. http://localhost:8080/payments
func NewClient(baseURL string, httpClient *http.Client) *Client {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}
	return &Client{baseURL: baseURL, httpClient: httpClient}
}

// Response is the subset of the simulator JSON we care about after a 200 OK.
type Response struct {
	Authorized          bool   `json:"authorized"`
	AuthorizationCode   string `json:"authorization_code"`
	ErrorMessage        string `json:"error_message"`
}

// SubmitPayment POSTs to the simulator and returns status code + decoded body (if JSON).
func (c *Client) SubmitPayment(ctx context.Context, body validation.BankSimulatorBody) (status int, resp *Response, rawBody []byte, err error) {
	payload, err := json.Marshal(body)
	if err != nil {
		return 0, nil, nil, fmt.Errorf("marshal bank request: %w", err)
	}

	req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL, bytes.NewReader(payload))
	if err != nil {
		return 0, nil, nil, fmt.Errorf("new request: %w", err)
	}
	req.Header.Set("Content-Type", "application/json")

	res, err := c.httpClient.Do(req)
	if err != nil {
		return 0, nil, nil, fmt.Errorf("http do: %w", err)
	}
	defer res.Body.Close()

	rawBody, _ = io.ReadAll(io.LimitReader(res.Body, 1<<20)) // 1 MiB cap

	if res.StatusCode != http.StatusOK {
		return res.StatusCode, nil, rawBody, nil
	}

	var parsed Response
	if err := json.Unmarshal(rawBody, &parsed); err != nil {
		return res.StatusCode, nil, rawBody, fmt.Errorf("decode bank json: %w", err)
	}
	return res.StatusCode, &parsed, rawBody, nil
}

Artículos relacionados