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
paddy@7 1 package client
paddy@7 2
paddy@7 3 import (
paddy@7 4 "bytes"
paddy@7 5 "encoding/json"
paddy@7 6 "errors"
paddy@7 7 "io"
paddy@7 8 "net/http"
paddy@7 9 "strings"
paddy@7 10 "time"
paddy@7 11
paddy@7 12 "code.secondbit.org/uuid.hg"
paddy@7 13
paddy@7 14 "code.secondbit.org/ducky/subscriptions.hg/api"
paddy@7 15 )
paddy@7 16
paddy@7 17 var (
paddy@7 18 ErrNilClient = errors.New("nil client wrapper")
paddy@7 19 ErrNilHTTPClient = errors.New("nil client")
paddy@7 20 )
paddy@7 21
paddy@7 22 type Client struct {
paddy@7 23 client *http.Client
paddy@7 24 address string
paddy@7 25 ID uuid.ID
paddy@7 26 }
paddy@7 27
paddy@7 28 func New(address string, id uuid.ID) *Client {
paddy@7 29 address = strings.TrimRight(address, "/")
paddy@7 30 return &Client{
paddy@7 31 address: address,
paddy@7 32 client: &http.Client{},
paddy@7 33 ID: id,
paddy@7 34 }
paddy@7 35 }
paddy@7 36
paddy@7 37 func (c *Client) do(method, url string, request interface{}, scopes []string, subject uuid.ID) (api.Response, error) {
paddy@7 38 if c == nil {
paddy@7 39 return api.Response{}, ErrNilClient
paddy@7 40 }
paddy@7 41 if c.client == nil {
paddy@7 42 return api.Response{}, ErrNilHTTPClient
paddy@7 43 }
paddy@7 44 var response api.Response
paddy@7 45 if !strings.HasPrefix(url, "http") {
paddy@7 46 url = strings.TrimLeft(url, "/")
paddy@7 47 url = "/" + url
paddy@7 48 url = c.address + url
paddy@7 49 }
paddy@7 50 var body io.Reader
paddy@7 51 if request != nil {
paddy@7 52 data, err := json.Marshal(request)
paddy@7 53 if err != nil {
paddy@7 54 return response, err
paddy@7 55 }
paddy@7 56 body = bytes.NewBuffer(data)
paddy@7 57 }
paddy@7 58 req, err := http.NewRequest(method, url, body)
paddy@7 59 if err != nil {
paddy@7 60 return response, err
paddy@7 61 }
paddy@7 62 req.Header.Set("Ducky-Scope", strings.Join(scopes, " "))
paddy@7 63 req.Header.Set("Ducky-Issuer", c.ID.String())
paddy@7 64 if subject != nil {
paddy@7 65 req.Header.Set("Ducky-Subject", subject.String())
paddy@7 66 }
paddy@7 67 req.Header.Set("Ducky-Expires", time.Now().Add(time.Hour).String())
paddy@7 68 req.Header.Set("Ducky-Issued-At", time.Now().String())
paddy@7 69 req.Header.Set("Ducky-Not-Before", time.Now().Add(-5*time.Minute).String())
paddy@7 70 resp, err := c.client.Do(req)
paddy@7 71 if err != nil {
paddy@7 72 return response, err
paddy@7 73 }
paddy@7 74 defer resp.Body.Close()
paddy@7 75 switch resp.Header.Get("Content-Type") {
paddy@7 76 case "application/json":
paddy@7 77 dec := json.NewDecoder(resp.Body)
paddy@7 78 err = dec.Decode(&response)
paddy@7 79 if err != nil {
paddy@7 80 return response, err
paddy@7 81 }
paddy@7 82 default:
paddy@7 83 dec := json.NewDecoder(resp.Body)
paddy@7 84 err = dec.Decode(&response)
paddy@7 85 if err != nil {
paddy@7 86 return response, err
paddy@7 87 }
paddy@7 88 }
paddy@7 89 return response, nil
paddy@7 90 }
paddy@7 91
paddy@7 92 func (c *Client) Get(url string, scopes []string, subject uuid.ID) (api.Response, error) {
paddy@7 93 return c.do("GET", url, nil, scopes, subject)
paddy@7 94 }
paddy@7 95
paddy@7 96 func (c *Client) Post(url string, request interface{}, scopes []string, subject uuid.ID) (api.Response, error) {
paddy@7 97 return c.do("POST", url, request, scopes, subject)
paddy@7 98 }
paddy@7 99
paddy@7 100 func (c *Client) Patch(url string, request interface{}, scopes []string, subject uuid.ID) (api.Response, error) {
paddy@7 101 return c.do("PATCH", url, request, scopes, subject)
paddy@7 102 }