ducky/subscriptions
7:9e138933e4ce Browse Files
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.
client/client.go client/subscription.go
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 +}
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/client/subscription.go Mon Jul 13 23:32:57 2015 -0400 2.3 @@ -0,0 +1,19 @@ 2.4 +package client 2.5 + 2.6 +import ( 2.7 + "code.secondbit.org/auth.hg" 2.8 + 2.9 + "code.secondbit.org/ducky/subscriptions.hg" 2.10 + "code.secondbit.org/ducky/subscriptions.hg/api" 2.11 +) 2.12 + 2.13 +func (c *Client) CreateSubscription(change subscriptions.SubscriptionChange) (subscriptions.Subscription, error) { 2.14 + resp, err := c.Post("/subscriptions/", change, auth.Scopes{api.ScopeSubscription, api.ScopeSubscriptionAdmin}.Strings(), change.UserID) 2.15 + if err != nil { 2.16 + return subscriptions.Subscription{}, err 2.17 + } 2.18 + if len(resp.Subscriptions) < 1 { 2.19 + return subscriptions.Subscription{}, subscriptions.ErrSubscriptionNotFound 2.20 + } 2.21 + return resp.Subscriptions[0], nil 2.22 +}