Files

84 lines
1.8 KiB
Go

package client
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"strings"
)
type Response struct {
StatusCode int
Header http.Header
Body []byte
}
type Client struct {
baseURL string
httpClient *http.Client
}
func New(baseURL string, httpClient *http.Client) *Client {
baseURL = strings.TrimSpace(baseURL)
baseURL = strings.TrimRight(baseURL, "/")
if httpClient == nil {
httpClient = http.DefaultClient
}
return &Client{
baseURL: baseURL,
httpClient: httpClient,
}
}
func (c *Client) Do(ctx context.Context, method, path string, headers http.Header, body []byte) (Response, error) {
url, err := c.resolveURL(path)
if err != nil {
return Response{}, err
}
req, err := http.NewRequestWithContext(ctx, method, url, bytes.NewReader(body))
if err != nil {
return Response{}, fmt.Errorf("build request: %w", err)
}
for key, values := range headers {
for _, value := range values {
req.Header.Add(key, value)
}
}
resp, err := c.httpClient.Do(req)
if err != nil {
return Response{}, fmt.Errorf("request %s %s: %w", method, url, err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return Response{}, fmt.Errorf("read response body: %w", err)
}
return Response{
StatusCode: resp.StatusCode,
Header: resp.Header.Clone(),
Body: respBody,
}, nil
}
func (c *Client) resolveURL(path string) (string, error) {
path = strings.TrimSpace(path)
if path == "" {
return "", fmt.Errorf("path is required")
}
if strings.HasPrefix(path, "http://") || strings.HasPrefix(path, "https://") {
return path, nil
}
if c.baseURL == "" {
return "", fmt.Errorf("base url is required for relative path %q", path)
}
if !strings.HasPrefix(path, "/") {
path = "/" + path
}
return c.baseURL + path, nil
}