git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/cloudflare/client.go (about) 1 package cloudflare 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "fmt" 8 "io" 9 "net/http" 10 11 "git.sr.ht/~pingoo/stdx/httpx" 12 ) 13 14 type Client struct { 15 httpClient *http.Client 16 apiToken string 17 baseURL string 18 } 19 20 func NewClient(apiToken string, httpClient *http.Client) *Client { 21 if httpClient == nil { 22 httpClient = httpx.DefaultClient() 23 } 24 25 return &Client{ 26 httpClient: httpClient, 27 apiToken: apiToken, 28 baseURL: "https://api.cloudflare.com", 29 } 30 } 31 32 type requestParams struct { 33 Method string 34 URL string 35 Payload interface{} 36 ServerToken *string 37 } 38 39 func (client *Client) request(ctx context.Context, params requestParams, dst interface{}) error { 40 url := client.baseURL + params.URL 41 var apiRes ApiResponse 42 43 req, err := http.NewRequestWithContext(ctx, params.Method, url, nil) 44 if err != nil { 45 return err 46 } 47 48 if params.Payload != nil { 49 payloadData, err := json.Marshal(params.Payload) 50 if err != nil { 51 return err 52 } 53 req.Body = io.NopCloser(bytes.NewBuffer(payloadData)) 54 } 55 56 req.Header.Add(httpx.HeaderAccept, httpx.MediaTypeJson) 57 req.Header.Add(httpx.HeaderContentType, httpx.MediaTypeJson) 58 req.Header.Add(httpx.HeaderAuthorization, "Bearer "+client.apiToken) 59 60 res, err := client.httpClient.Do(req) 61 if err != nil { 62 return err 63 } 64 defer res.Body.Close() 65 66 err = json.NewDecoder(res.Body).Decode(&apiRes) 67 if err != nil { 68 err = fmt.Errorf("cloudflare: decoding JSON body: %w", err) 69 return err 70 } 71 72 if len(apiRes.Errors) != 0 { 73 err = fmt.Errorf("cloudflare: %s", apiRes.Errors[0].Error()) 74 return err 75 } 76 77 if dst != nil { 78 err = json.Unmarshal(apiRes.Result, dst) 79 if err != nil { 80 err = fmt.Errorf("cloudflare: decoding JSON result: %w", err) 81 return err 82 } 83 } 84 85 return nil 86 } 87 88 type ApiResponse struct { 89 Result json.RawMessage `json:"result"` 90 Success bool `json:"success"` 91 Errors []ApiError `json:"errors"` 92 } 93 94 type ApiError struct { 95 Code string `json:"code"` 96 Message string `json:"message"` 97 } 98 99 func (res ApiError) Error() string { 100 return res.Message 101 }