149 lines
3.4 KiB
Go
149 lines
3.4 KiB
Go
package dynect
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"net/http"
|
|
)
|
|
|
|
const (
|
|
DynAPIPrefix = "https://api.dynect.net/REST"
|
|
)
|
|
|
|
// A client for use with DynECT's REST API.
|
|
type Client struct {
|
|
Token string
|
|
CustomerName string
|
|
httpclient *http.Client
|
|
verbose bool
|
|
}
|
|
|
|
// Creates a new Httpclient.
|
|
func NewClient(customerName string) *Client {
|
|
return &Client{
|
|
CustomerName: customerName,
|
|
httpclient: &http.Client{}}
|
|
}
|
|
|
|
// Enable, or disable verbose output from the client.
|
|
//
|
|
// This will enable (or disable) logging messages that explain what the client
|
|
// is about to do, like the endpoint it is about to make a request to. If the
|
|
// request fails with an unexpected HTTP response code, then the response body
|
|
// will be logged out, as well.
|
|
func (c *Client) Verbose(p bool) {
|
|
c.verbose = p
|
|
}
|
|
|
|
// Establishes a new session with the DynECT API.
|
|
func (c *Client) Login(username, password string) error {
|
|
var req = LoginBlock{
|
|
Username: username,
|
|
Password: password,
|
|
CustomerName: c.CustomerName}
|
|
|
|
var resp LoginResponse
|
|
|
|
err := c.Do("POST", "Session", req, &resp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
c.Token = resp.Data.Token
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) LoggedIn() bool {
|
|
return len(c.Token) > 0
|
|
}
|
|
|
|
func (c *Client) Logout() error {
|
|
return c.Do("DELETE", "Session", nil, nil)
|
|
}
|
|
|
|
func (c *Client) Do(method, endpoint string, requestData, responseData interface{}) error {
|
|
// Throw an error if the user tries to make a request if the client is
|
|
// logged out/unauthenticated, but make an exemption for when the
|
|
// caller is trying to log in.
|
|
if !c.LoggedIn() && method != "POST" && endpoint != "Session" {
|
|
return errors.New("Will not perform request; httpclient is closed")
|
|
}
|
|
|
|
var err error
|
|
|
|
// Marshal the request data into a byte slice.
|
|
if c.verbose {
|
|
log.Println("Marshaling request data")
|
|
}
|
|
var js []byte
|
|
if requestData != nil {
|
|
js, err = json.Marshal(requestData)
|
|
} else {
|
|
js = []byte("")
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Create a new http.Request object, and set the necessary headers to
|
|
// authorize the request, and specify the content type.
|
|
url := fmt.Sprintf("%s/%s", DynAPIPrefix, endpoint)
|
|
var req *http.Request
|
|
req, err = http.NewRequest(method, url, bytes.NewReader(js))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
req.Header.Set("Auth-Token", c.Token)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
if c.verbose {
|
|
log.Printf("Making %s request to %q", method, url)
|
|
}
|
|
|
|
var resp *http.Response
|
|
resp, err = c.httpclient.Do(req)
|
|
if err != nil {
|
|
if c.verbose {
|
|
respBody, _ := ioutil.ReadAll(resp.Body)
|
|
log.Printf("%s", string(respBody))
|
|
}
|
|
return err
|
|
} else if resp.StatusCode != 200 {
|
|
if c.verbose {
|
|
// Print out the response body.
|
|
respBody, _ := ioutil.ReadAll(resp.Body)
|
|
log.Printf("%s", string(respBody))
|
|
}
|
|
return errors.New(fmt.Sprintf("Bad response, got %q", resp.Status))
|
|
}
|
|
|
|
// Unmarshal the response data into the provided struct.
|
|
if c.verbose {
|
|
log.Println("Reading in response data")
|
|
}
|
|
var respBody []byte
|
|
respBody, err = ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if c.verbose {
|
|
log.Println("Unmarshaling response data")
|
|
}
|
|
err = json.Unmarshal(respBody, &responseData)
|
|
if err != nil {
|
|
respBody, _ := ioutil.ReadAll(resp.Body)
|
|
if resp.ContentLength == 0 || resp.ContentLength == -1 {
|
|
log.Println("Zero-length content body")
|
|
} else {
|
|
log.Printf("%s", string(respBody))
|
|
}
|
|
}
|
|
|
|
return err
|
|
}
|