ducky/subscriptions
2015-07-13
Child:8eb19bcbf17d
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.
| 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 } |