zoom-lib-golang/zoom-lib-golang

View on GitHub
client.go

Summary

Maintainability
A
0 mins
Test Coverage
package zoom

import (
    "bytes"
    "encoding/json"
    "errors"
    "io/ioutil"
    "log"
    "net/http"
    "net/url"
    "time"

    "github.com/google/go-querystring/query"
)

const (
    apiURI     = "api.zoom.us"
    apiVersion = "/v2"
)

var (
    // Debug causes debugging message to be printed, using the log package,
    // when set to true
    Debug = false

    // APIKey is a package-wide API key, used when no client is instantiated
    APIKey string

    // APISecret is a package-wide API secret, used when no client is instantiated
    APISecret string

    defaultClient *Client
)

// Client is responsible for making API requests
type Client struct {
    Key       string
    Secret    string
    Transport http.RoundTripper
    Timeout   time.Duration // set to value > 0 to enable a request timeout
    endpoint  string
}

// NewClient returns a new API client
func NewClient(apiKey string, apiSecret string) *Client {
    var uri = url.URL{
        Scheme: "https",
        Host:   apiURI,
        Path:   apiVersion,
    }

    return &Client{
        Key:      apiKey,
        Secret:   apiSecret,
        endpoint: uri.String(),
    }
}

type requestV2Opts struct {
    Client         *Client
    Method         HTTPMethod
    URLParameters  interface{}
    Path           string
    DataParameters interface{}
    Ret            interface{}
    // HeadResponse represents responses that don't have a body
    HeadResponse bool
}

func initializeDefault(c *Client) *Client {
    if c == nil {
        if defaultClient == nil {
            defaultClient = NewClient(APIKey, APISecret)
        }

        return defaultClient
    }

    return c
}

func (c *Client) executeRequest(opts requestV2Opts) (*http.Response, error) {
    client := c.httpClient()
    req, err := c.addRequestAuth(c.httpRequest(opts))
    if err != nil {
        return nil, err
    }

    req.Header.Add("Content-Type", "application/json")

    return client.Do(req)
}

func (c *Client) httpRequest(opts requestV2Opts) (*http.Request, error) {
    var buf bytes.Buffer

    // encode body parameters if any
    if err := json.NewEncoder(&buf).Encode(&opts.DataParameters); err != nil {
        return nil, err
    }

    // set URL parameters
    values, err := query.Values(opts.URLParameters)
    if err != nil {
        return nil, err
    }

    // set request URL
    requestURL := c.endpoint + opts.Path
    if len(values) > 0 {
        requestURL += "?" + values.Encode()
    }

    if Debug {
        log.Printf("Request URL: %s", requestURL)
        log.Printf("URL Parameters: %s", values.Encode())
        log.Printf("Body Parameters: %s", buf.String())
    }

    // create HTTP request
    return http.NewRequest(string(opts.Method), requestURL, &buf)
}

func (c *Client) httpClient() *http.Client {
    client := &http.Client{Transport: c.Transport}
    if c.Timeout > 0 {
        client.Timeout = c.Timeout
    }

    return client
}

func (c *Client) requestV2(opts requestV2Opts) error {
    // make sure the defaultClient is not nil if we are using it
    c = initializeDefault(c)

    // execute HTTP request
    resp, err := c.executeRequest(opts)
    if err != nil {
        return err
    }

    // If there is no body in response
    if opts.HeadResponse {
        return c.requestV2HeadOnly(resp)
    }

    return c.requestV2WithBody(opts, resp)
}

func (c *Client) requestV2WithBody(opts requestV2Opts, resp *http.Response) error {
    // read HTTP response
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return err
    }

    if Debug {
        log.Printf("Response Body: %s", string(body))
    }

    // check for Zoom errors in the response
    if err := checkError(body); err != nil {
        return err
    }

    // unmarshal the response body into the return object
    return json.Unmarshal(body, &opts.Ret)
}

func (c *Client) requestV2HeadOnly(resp *http.Response) error {
    if resp.StatusCode != 204 {
        return errors.New(resp.Status)
    }

    // there were no errors, just return
    return nil
}