package dify import ( "bytes" "context" "encoding/json" "fmt" "io" "net/http" "time" ) type Client struct { baseURL string httpClient *http.Client } func NewClient(baseURL string) *Client { return &Client{ baseURL: baseURL, httpClient: &http.Client{ Timeout: 120 * time.Second, }, } } func (c *Client) do(ctx context.Context, method, path, apiKey string, body any) (*http.Response, error) { var bodyReader io.Reader if body != nil { data, err := json.Marshal(body) if err != nil { return nil, fmt.Errorf("marshal request: %w", err) } bodyReader = bytes.NewReader(data) } req, err := http.NewRequestWithContext(ctx, method, c.baseURL+path, bodyReader) if err != nil { return nil, fmt.Errorf("create request: %w", err) } req.Header.Set("Authorization", "Bearer "+apiKey) req.Header.Set("Content-Type", "application/json") resp, err := c.httpClient.Do(req) if err != nil { return nil, fmt.Errorf("execute request: %w", err) } if resp.StatusCode >= 400 { defer resp.Body.Close() var apiErr APIError if err := json.NewDecoder(resp.Body).Decode(&apiErr); err != nil { return nil, fmt.Errorf("dify API error (status %d)", resp.StatusCode) } apiErr.Status = resp.StatusCode return nil, &apiErr } return resp, nil } func (c *Client) doJSON(ctx context.Context, method, path, apiKey string, body any, result any) error { resp, err := c.do(ctx, method, path, apiKey, body) if err != nil { return err } defer resp.Body.Close() if result != nil { return json.NewDecoder(resp.Body).Decode(result) } return nil }