git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/postmark/client.go (about)

     1  package postmark
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"errors"
     8  	"io"
     9  	"net/http"
    10  
    11  	"git.sr.ht/~pingoo/stdx/httpx"
    12  )
    13  
    14  type Client struct {
    15  	httpClient      *http.Client
    16  	accountApiToken string
    17  	baseURL         string
    18  }
    19  
    20  func NewClient(accountApiToken string, httpClient *http.Client) *Client {
    21  	if httpClient == nil {
    22  		httpClient = httpx.DefaultClient()
    23  	}
    24  
    25  	return &Client{
    26  		httpClient:      httpClient,
    27  		accountApiToken: accountApiToken,
    28  		baseURL:         "https://api.postmarkapp.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  
    42  	req, err := http.NewRequestWithContext(ctx, params.Method, url, nil)
    43  	if err != nil {
    44  		return err
    45  	}
    46  
    47  	if params.Payload != nil {
    48  		payloadData, err := json.Marshal(params.Payload)
    49  		if err != nil {
    50  			return err
    51  		}
    52  		req.Body = io.NopCloser(bytes.NewBuffer(payloadData))
    53  	}
    54  
    55  	req.Header.Add(httpx.HeaderAccept, httpx.MediaTypeJson)
    56  	req.Header.Add(httpx.HeaderContentType, httpx.MediaTypeJson)
    57  
    58  	if params.ServerToken != nil {
    59  		req.Header.Add("X-Postmark-Server-Token", *params.ServerToken)
    60  	} else {
    61  		req.Header.Add("X-Postmark-Account-Token", client.accountApiToken)
    62  	}
    63  
    64  	res, err := client.httpClient.Do(req)
    65  	if err != nil {
    66  		return err
    67  	}
    68  	defer res.Body.Close()
    69  
    70  	body, err := io.ReadAll(res.Body)
    71  	if err != nil {
    72  		return err
    73  	}
    74  
    75  	if dst == nil || res.StatusCode > 399 {
    76  		var apiRes APIError
    77  		err = json.Unmarshal(body, &apiRes)
    78  		if err != nil {
    79  			return err
    80  		}
    81  		if apiRes.ErrorCode != 0 {
    82  			err = errors.New(apiRes.Message)
    83  			return err
    84  		}
    85  	} else {
    86  		err = json.Unmarshal(body, dst)
    87  	}
    88  
    89  	return err
    90  }
    91  
    92  type APIError struct {
    93  	ErrorCode int64
    94  	Message   string
    95  }
    96  
    97  func (res APIError) Error() string {
    98  	return res.Message
    99  }