Files
s01e03/internal/infrastructure/packages/api_client.go
2026-03-12 19:17:00 +01:00

185 lines
4.9 KiB
Go

package packages
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"github.com/paramah/ai_devs4/s01e03/internal/domain"
)
// APIClient implements domain.PackageClient
type APIClient struct {
baseURL string
apiKey string
client *http.Client
verbose bool
}
// NewAPIClient creates a new package API client
func NewAPIClient(baseURL, apiKey string, verbose bool) *APIClient {
return &APIClient{
baseURL: baseURL,
apiKey: apiKey,
client: &http.Client{},
verbose: verbose,
}
}
type checkRequest struct {
APIKey string `json:"apikey"`
Action string `json:"action"`
PackageID string `json:"packageid"`
}
type checkResponse struct {
Status string `json:"status"`
Location string `json:"location,omitempty"`
Error string `json:"error,omitempty"`
}
type redirectRequest struct {
APIKey string `json:"apikey"`
Action string `json:"action"`
PackageID string `json:"packageid"`
Destination string `json:"destination"`
Code string `json:"code"`
}
type redirectResponse struct {
Status string `json:"status"`
Message string `json:"message,omitempty"`
Confirmation string `json:"confirmation,omitempty"`
Error string `json:"error,omitempty"`
}
// Check checks the status of a package
func (c *APIClient) Check(ctx context.Context, packageID string) (*domain.PackageStatus, error) {
reqBody := checkRequest{
APIKey: c.apiKey,
Action: "check",
PackageID: packageID,
}
jsonData, err := json.Marshal(reqBody)
if err != nil {
return nil, fmt.Errorf("marshaling request: %w", err)
}
if c.verbose {
var prettyJSON bytes.Buffer
if err := json.Indent(&prettyJSON, jsonData, "", " "); err == nil {
log.Printf("\n========== PACKAGE API CHECK REQUEST ==========\nURL: %s\nBody:\n%s\n===============================================\n", c.baseURL, prettyJSON.String())
}
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL, bytes.NewBuffer(jsonData))
if err != nil {
return nil, fmt.Errorf("creating request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.client.Do(req)
if err != nil {
return nil, fmt.Errorf("sending request: %w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("reading response: %w", err)
}
if c.verbose {
var prettyJSON bytes.Buffer
if err := json.Indent(&prettyJSON, body, "", " "); err == nil {
log.Printf("\n========== PACKAGE API CHECK RESPONSE ==========\nStatus: %d\nBody:\n%s\n================================================\n", resp.StatusCode, prettyJSON.String())
}
}
var apiResp checkResponse
if err := json.Unmarshal(body, &apiResp); err != nil {
return nil, fmt.Errorf("unmarshaling response: %w", err)
}
if apiResp.Error != "" {
return nil, fmt.Errorf("API error: %s", apiResp.Error)
}
return &domain.PackageStatus{
PackageID: packageID,
Status: apiResp.Status,
Location: apiResp.Location,
}, nil
}
// Redirect redirects a package to a new destination and returns the confirmation message
func (c *APIClient) Redirect(ctx context.Context, packageID, destination, code string) (string, error) {
reqBody := redirectRequest{
APIKey: c.apiKey,
Action: "redirect",
PackageID: packageID,
Destination: destination,
Code: code,
}
jsonData, err := json.Marshal(reqBody)
if err != nil {
return "", fmt.Errorf("marshaling request: %w", err)
}
if c.verbose {
var prettyJSON bytes.Buffer
if err := json.Indent(&prettyJSON, jsonData, "", " "); err == nil {
log.Printf("\n========== PACKAGE API REDIRECT REQUEST ==========\nURL: %s\nBody:\n%s\n==================================================\n", c.baseURL, prettyJSON.String())
}
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL, bytes.NewBuffer(jsonData))
if err != nil {
return "", fmt.Errorf("creating request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.client.Do(req)
if err != nil {
return "", fmt.Errorf("sending request: %w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("reading response: %w", err)
}
if c.verbose {
var prettyJSON bytes.Buffer
if err := json.Indent(&prettyJSON, body, "", " "); err == nil {
log.Printf("\n========== PACKAGE API REDIRECT RESPONSE ==========\nStatus: %d\nBody:\n%s\n===================================================\n", resp.StatusCode, prettyJSON.String())
}
}
var apiResp redirectResponse
if err := json.Unmarshal(body, &apiResp); err != nil {
return "", fmt.Errorf("unmarshaling response: %w", err)
}
if apiResp.Error != "" {
return "", fmt.Errorf("API error: %s", apiResp.Error)
}
// Return the confirmation code
if apiResp.Confirmation != "" {
return apiResp.Confirmation, nil
}
// Fallback to message if confirmation is not present
return apiResp.Message, nil
}