gitlab.com/SiaPrime/SiaPrime@v1.4.1/node/api/client_test.go (about)

     1  package api
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"io"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"strings"
    10  )
    11  
    12  // Client holds fields to make requests to a Sia API.
    13  type Client struct {
    14  	address  string
    15  	password string
    16  }
    17  
    18  // NewClient creates a new api.Client using the provided address and password.
    19  // If password is not the empty string, HTTP basic authentication will be used
    20  // to communicate with the API.
    21  func NewClient(address string, password string) *Client {
    22  	return &Client{
    23  		address:  address,
    24  		password: password,
    25  	}
    26  }
    27  
    28  // Get requests the resource at `resource` and decodes it into `obj`, returning an
    29  // error if requesting or decoding the resource fails.  A non-2xx status code
    30  // constitutes a request failure.
    31  func (c *Client) Get(resource string, obj interface{}) error {
    32  	url := "http://" + c.address + resource
    33  	req, err := http.NewRequest("GET", url, nil)
    34  	if err != nil {
    35  		return err
    36  	}
    37  	req.Header.Set("User-Agent", "SiaPrime-Agent")
    38  	if c.password != "" {
    39  		req.SetBasicAuth("", c.password)
    40  	}
    41  	res, err := http.DefaultClient.Do(req)
    42  	if err != nil {
    43  		return err
    44  	}
    45  	defer func() {
    46  		// res.Body should always be fully read even when discarding its content,
    47  		// such that the underlying connection can be reused.
    48  		io.Copy(ioutil.Discard, res.Body)
    49  		res.Body.Close()
    50  	}()
    51  
    52  	if res.StatusCode == http.StatusNotFound {
    53  		return errors.New("API call not recognized: " + resource)
    54  	}
    55  
    56  	// Decode the body as an Error and return this error if the status code is
    57  	// not 2xx.
    58  	if res.StatusCode < 200 || res.StatusCode > 299 {
    59  		var apiErr Error
    60  		err = json.NewDecoder(res.Body).Decode(&apiErr)
    61  		if err != nil {
    62  			return err
    63  		}
    64  		return apiErr
    65  	}
    66  
    67  	if res.StatusCode != http.StatusNoContent && obj != nil {
    68  		return json.NewDecoder(res.Body).Decode(obj)
    69  	}
    70  	return nil
    71  }
    72  
    73  // Post makes a POST request to the resource at `resource`, using `data` as the
    74  // request body.  The response, if provided, will be decoded into `obj`.
    75  func (c *Client) Post(resource string, data string, obj interface{}) error {
    76  	url := "http://" + c.address + resource
    77  	req, err := http.NewRequest("POST", url, strings.NewReader(data))
    78  	if err != nil {
    79  		return err
    80  	}
    81  	req.Header.Set("User-Agent", "SiaPrime-Agent")
    82  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
    83  	if c.password != "" {
    84  		req.SetBasicAuth("", c.password)
    85  	}
    86  	res, err := http.DefaultClient.Do(req)
    87  	if err != nil {
    88  		return err
    89  	}
    90  	defer func() {
    91  		// res.Body should always be fully read even when discarding its content,
    92  		// such that the underlying connection can be reused.
    93  		io.Copy(ioutil.Discard, res.Body)
    94  		res.Body.Close()
    95  	}()
    96  
    97  	if res.StatusCode == http.StatusNotFound {
    98  		return errors.New("API call not recognized: " + resource)
    99  	}
   100  
   101  	if res.StatusCode < 200 || res.StatusCode > 299 {
   102  		var apiErr Error
   103  		err = json.NewDecoder(res.Body).Decode(&apiErr)
   104  		if err != nil {
   105  			return err
   106  		}
   107  		return apiErr
   108  	}
   109  
   110  	if res.StatusCode != http.StatusNoContent && obj != nil {
   111  		return json.NewDecoder(res.Body).Decode(&obj)
   112  	}
   113  	return nil
   114  }