ducky/subscriptions

Paddy 2015-07-13 Child:8eb19bcbf17d

7:9e138933e4ce Go to Latest

ducky/subscriptions/client/client.go

Create a client for working with subscriptions. We mostly copied our code.secondbit.org/auth.hg/client package to create a simple client library for communicating with our Subscriptions API. Right now, the client only has support for creating a subscription. It remains untested, but it builds.

History
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/client/client.go	Mon Jul 13 23:32:57 2015 -0400
     1.3 @@ -0,0 +1,102 @@
     1.4 +package client
     1.5 +
     1.6 +import (
     1.7 +	"bytes"
     1.8 +	"encoding/json"
     1.9 +	"errors"
    1.10 +	"io"
    1.11 +	"net/http"
    1.12 +	"strings"
    1.13 +	"time"
    1.14 +
    1.15 +	"code.secondbit.org/uuid.hg"
    1.16 +
    1.17 +	"code.secondbit.org/ducky/subscriptions.hg/api"
    1.18 +)
    1.19 +
    1.20 +var (
    1.21 +	ErrNilClient     = errors.New("nil client wrapper")
    1.22 +	ErrNilHTTPClient = errors.New("nil client")
    1.23 +)
    1.24 +
    1.25 +type Client struct {
    1.26 +	client  *http.Client
    1.27 +	address string
    1.28 +	ID      uuid.ID
    1.29 +}
    1.30 +
    1.31 +func New(address string, id uuid.ID) *Client {
    1.32 +	address = strings.TrimRight(address, "/")
    1.33 +	return &Client{
    1.34 +		address: address,
    1.35 +		client:  &http.Client{},
    1.36 +		ID:      id,
    1.37 +	}
    1.38 +}
    1.39 +
    1.40 +func (c *Client) do(method, url string, request interface{}, scopes []string, subject uuid.ID) (api.Response, error) {
    1.41 +	if c == nil {
    1.42 +		return api.Response{}, ErrNilClient
    1.43 +	}
    1.44 +	if c.client == nil {
    1.45 +		return api.Response{}, ErrNilHTTPClient
    1.46 +	}
    1.47 +	var response api.Response
    1.48 +	if !strings.HasPrefix(url, "http") {
    1.49 +		url = strings.TrimLeft(url, "/")
    1.50 +		url = "/" + url
    1.51 +		url = c.address + url
    1.52 +	}
    1.53 +	var body io.Reader
    1.54 +	if request != nil {
    1.55 +		data, err := json.Marshal(request)
    1.56 +		if err != nil {
    1.57 +			return response, err
    1.58 +		}
    1.59 +		body = bytes.NewBuffer(data)
    1.60 +	}
    1.61 +	req, err := http.NewRequest(method, url, body)
    1.62 +	if err != nil {
    1.63 +		return response, err
    1.64 +	}
    1.65 +	req.Header.Set("Ducky-Scope", strings.Join(scopes, " "))
    1.66 +	req.Header.Set("Ducky-Issuer", c.ID.String())
    1.67 +	if subject != nil {
    1.68 +		req.Header.Set("Ducky-Subject", subject.String())
    1.69 +	}
    1.70 +	req.Header.Set("Ducky-Expires", time.Now().Add(time.Hour).String())
    1.71 +	req.Header.Set("Ducky-Issued-At", time.Now().String())
    1.72 +	req.Header.Set("Ducky-Not-Before", time.Now().Add(-5*time.Minute).String())
    1.73 +	resp, err := c.client.Do(req)
    1.74 +	if err != nil {
    1.75 +		return response, err
    1.76 +	}
    1.77 +	defer resp.Body.Close()
    1.78 +	switch resp.Header.Get("Content-Type") {
    1.79 +	case "application/json":
    1.80 +		dec := json.NewDecoder(resp.Body)
    1.81 +		err = dec.Decode(&response)
    1.82 +		if err != nil {
    1.83 +			return response, err
    1.84 +		}
    1.85 +	default:
    1.86 +		dec := json.NewDecoder(resp.Body)
    1.87 +		err = dec.Decode(&response)
    1.88 +		if err != nil {
    1.89 +			return response, err
    1.90 +		}
    1.91 +	}
    1.92 +	return response, nil
    1.93 +}
    1.94 +
    1.95 +func (c *Client) Get(url string, scopes []string, subject uuid.ID) (api.Response, error) {
    1.96 +	return c.do("GET", url, nil, scopes, subject)
    1.97 +}
    1.98 +
    1.99 +func (c *Client) Post(url string, request interface{}, scopes []string, subject uuid.ID) (api.Response, error) {
   1.100 +	return c.do("POST", url, request, scopes, subject)
   1.101 +}
   1.102 +
   1.103 +func (c *Client) Patch(url string, request interface{}, scopes []string, subject uuid.ID) (api.Response, error) {
   1.104 +	return c.do("PATCH", url, request, scopes, subject)
   1.105 +}