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  }