ducky/subscriptions

Paddy 2015-09-27 Parent:8eb19bcbf17d Child:7eef47ecc01c

11:0ae1ff0ee306 Go to Latest

ducky/subscriptions/client/client.go

Add comments, move ChangingSystemProperties to the api package. Add comments to all our exported types and variables in subscription.go, both to make golint happy and because it's good to have comments. Move the subscriptions.ChangingSystemProperties helper to api.changingSystemProperties, because it returns API-specific strings and there's no real reason it has to be in the subscriptions package--everything it needs to work on is exported.

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