package api import ( "bytes" "encoding/json" "fmt" "io" "net/http" "time" "github.com/claudia/docs-cli/internal/config" "github.com/claudia/docs-cli/pkg/types" ) // Client is the API client type Client struct { BaseURL string Token string HTTPClient *http.Client Timeout time.Duration } // NewClient creates a new API client func NewClient() (*Client, error) { cfg := config.GetConfig() if cfg == nil { cfg = &config.Config{Server: "http://localhost:8000", Timeout: "30s"} } timeout, err := time.ParseDuration(cfg.Timeout) if err != nil { timeout = 30 * time.Second } return &Client{ BaseURL: cfg.Server + "/api/v1", Token: cfg.Token, HTTPClient: &http.Client{ Timeout: timeout, }, Timeout: timeout, }, nil } // SetToken sets the authentication token func (c *Client) SetToken(token string) { c.Token = token } // doRequest performs an HTTP request func (c *Client) doRequest(method, path string, body interface{}) (*http.Response, error) { var reqBody io.Reader if body != nil { jsonData, err := json.Marshal(body) if err != nil { return nil, fmt.Errorf("failed to marshal request body: %w", err) } reqBody = bytes.NewBuffer(jsonData) } url := c.BaseURL + path req, err := http.NewRequest(method, url, reqBody) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } req.Header.Set("Content-Type", "application/json") if c.Token != "" { req.Header.Set("Authorization", "Bearer "+c.Token) } return c.HTTPClient.Do(req) } // DoRequest performs an HTTP request (exported for auth package) func (c *Client) DoRequest(method, path string, body interface{}) (*http.Response, error) { return c.doRequest(method, path, body) } // Response parses the API response type Response struct { Success bool Data interface{} Error *types.ErrorInfo } func parseResponse(resp *http.Response) (*types.Response, error) { body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("failed to read response body: %w", err) } var apiResp types.Response if err := json.Unmarshal(body, &apiResp); err != nil { return nil, fmt.Errorf("failed to parse response JSON: %w", err) } return &apiResp, nil } func handleError(resp *http.Response, body []byte) error { var apiResp types.Response if err := json.Unmarshal(body, &apiResp); err != nil { return fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body)) } if apiResp.Error != nil { return fmt.Errorf("%s: %s", apiResp.Error.Code, apiResp.Error.Message) } return fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body)) }