package api import ( "encoding/json" "fmt" "net/http" "net/url" "strconv" "strings" "time" ) type Client struct { baseURL string httpClient *http.Client apiKey string } func NewClient(baseURL, apiKey string) *Client { return &Client{ baseURL: strings.TrimRight(baseURL, "/"), apiKey: apiKey, httpClient: &http.Client{ Timeout: 10 * time.Second, }, } } func (c *Client) newRequest(method, path string) (*http.Request, error) { req, err := http.NewRequest(method, c.baseURL+path, nil) if err != nil { return nil, err } req.Header.Set("Authorization", "Bearer "+c.apiKey) req.Header.Set("Accept", "application/json") return req, nil } func (c *Client) do(req *http.Request, out any) error { resp, err := c.httpClient.Do(req) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode >= 400 { var e struct { Error string `json:"error"` } _ = json.NewDecoder(resp.Body).Decode(&e) if e.Error != "" { return fmt.Errorf("server returned %d: %s", resp.StatusCode, e.Error) } return fmt.Errorf("server returned %d", resp.StatusCode) } if out != nil { return json.NewDecoder(resp.Body).Decode(out) } return nil } // ListAlerts fetches alerts from the server. status may be "firing", "resolved", or "" for all. func (c *Client) ListAlerts(status string, limit int) ([]Alert, error) { q := url.Values{} if status != "" { q.Set("status", status) } if limit > 0 { q.Set("limit", strconv.Itoa(limit)) } path := "/api/alerts" if len(q) > 0 { path += "?" + q.Encode() } req, err := c.newRequest(http.MethodGet, path) if err != nil { return nil, err } var alerts []Alert return alerts, c.do(req, &alerts) } // GetAlertStats fetches aggregate alert counts. func (c *Client) GetAlertStats() (*AlertStats, error) { req, err := c.newRequest(http.MethodGet, "/api/stats/alerts") if err != nil { return nil, err } var stats AlertStats return &stats, c.do(req, &stats) } // HealthCheck calls GET /healthz (unauthenticated path, no auth needed but we send it anyway). func (c *Client) HealthCheck() error { req, err := http.NewRequest(http.MethodGet, c.baseURL+"/healthz", nil) if err != nil { return err } resp, err := c.httpClient.Do(req) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return fmt.Errorf("health check failed: %s", resp.Status) } return nil }