gitlab.com/jokerrs1/Sia@v1.3.2/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", "Sia-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", "Sia-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 }