github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/pkg/manager/client.go (about)

     1  // Package manager is used for interacting with the cloudery.
     2  package manager
     3  
     4  import (
     5  	"bytes"
     6  	"context"
     7  	"encoding/json"
     8  	"errors"
     9  	"io"
    10  	"net/http"
    11  	"time"
    12  
    13  	"github.com/labstack/echo/v4"
    14  	"golang.org/x/oauth2"
    15  )
    16  
    17  // tokenSource implements the oauth2.TokenSource interface
    18  type tokenSource struct {
    19  	token string
    20  }
    21  
    22  func (t *tokenSource) Token() (*oauth2.Token, error) {
    23  	token := &oauth2.Token{
    24  		AccessToken: t.token,
    25  	}
    26  	return token, nil
    27  }
    28  
    29  // APIClient is an http client that can be used to query the API of the
    30  // manager.
    31  type APIClient struct {
    32  	baseURL string
    33  	client  *http.Client
    34  }
    35  
    36  // NewAPIClient builds a new client for the manager API
    37  func NewAPIClient(baseURL, token string) *APIClient {
    38  	tokenSource := &tokenSource{token: token}
    39  	client := oauth2.NewClient(context.Background(), tokenSource)
    40  	client.Timeout = 15 * time.Second
    41  	return &APIClient{
    42  		baseURL: baseURL,
    43  		client:  client,
    44  	}
    45  }
    46  
    47  // Do makes a request to the manager API
    48  func (c *APIClient) Do(method, url string, body io.Reader) (*http.Response, error) {
    49  	req, err := http.NewRequest(method, c.baseURL+url, body)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	if body != nil {
    54  		req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
    55  	}
    56  	return c.client.Do(req)
    57  }
    58  
    59  // Get makes a GET request to the manager API
    60  func (c *APIClient) Get(url string) (map[string]interface{}, error) {
    61  	res, err := c.Do(http.MethodGet, url, nil)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	defer res.Body.Close()
    66  	if res.StatusCode >= 400 {
    67  		return nil, errors.New(res.Status)
    68  	}
    69  	var data map[string]interface{}
    70  	if err := json.NewDecoder(res.Body).Decode(&data); err != nil {
    71  		return nil, err
    72  	}
    73  	return data, nil
    74  }
    75  
    76  // Post makes a POST request to the manager API
    77  func (c *APIClient) Post(url string, body io.Reader) error {
    78  	res, err := c.Do(http.MethodPost, url, body)
    79  	if err != nil {
    80  		return err
    81  	}
    82  	if err := res.Body.Close(); err != nil {
    83  		return err
    84  	}
    85  	if res.StatusCode >= 400 {
    86  		return errors.New(res.Status)
    87  	}
    88  	return nil
    89  }
    90  
    91  // Put makes a PUT request to the manager API
    92  func (c *APIClient) Put(url string, params map[string]interface{}) error {
    93  	body, err := json.Marshal(params)
    94  	if err != nil {
    95  		return err
    96  	}
    97  	reader := bytes.NewReader(body)
    98  	res, err := c.Do(http.MethodPut, url, reader)
    99  	if err != nil {
   100  		return err
   101  	}
   102  	if err := res.Body.Close(); err != nil {
   103  		return err
   104  	}
   105  	if res.StatusCode >= 400 {
   106  		return errors.New(res.Status)
   107  	}
   108  	return nil
   109  }
   110  
   111  // Delete makes a DELETE request to the manager API
   112  func (c *APIClient) Delete(url string) error {
   113  	res, err := c.Do(http.MethodDelete, url, nil)
   114  	if err != nil {
   115  		return err
   116  	}
   117  	if err := res.Body.Close(); err != nil {
   118  		return err
   119  	}
   120  	if res.StatusCode >= 400 {
   121  		return errors.New(res.Status)
   122  	}
   123  	return nil
   124  }