api.go
changeset 155 0c581e0108da
parent 150 cd328b30af77
child 159 408aa794d9bb
equal deleted inserted replaced
154:eb83fd052cc5 155:0c581e0108da
    11 	"bytes"
    11 	"bytes"
    12 	"encoding/json"
    12 	"encoding/json"
    13 	"fmt"
    13 	"fmt"
    14 	"net/http"
    14 	"net/http"
    15 	"net/url"
    15 	"net/url"
       
    16 	"regexp"
    16 	"strconv"
    17 	"strconv"
    17 	"strings"
    18 	"strings"
    18 
    19 
    19 	"github.com/sendgrid/rest"
    20 	"github.com/sendgrid/rest"
    20 )
    21 )
       
    22 
       
    23 type apiLinks struct {
       
    24 	next, prev *LimitParams
       
    25 }
       
    26 
       
    27 func parseLink(links []string) (*apiLinks, error) {
       
    28 	if len(links) == 0 {
       
    29 		return nil, nil
       
    30 	}
       
    31 
       
    32 	al := new(apiLinks)
       
    33 	linkRegex := regexp.MustCompile(`<([^>]+)>; rel="([^"]+)`)
       
    34 	for _, l := range links {
       
    35 		m := linkRegex.FindAllStringSubmatch(l, -1)
       
    36 		for _, submatch := range m {
       
    37 			if len(submatch) != 3 {
       
    38 				continue
       
    39 			}
       
    40 			// Parse URL
       
    41 			u, err := url.Parse(submatch[1])
       
    42 			if err != nil {
       
    43 				return al, err
       
    44 			}
       
    45 			var lp *LimitParams
       
    46 			since := u.Query().Get("since_id")
       
    47 			max := u.Query().Get("max_id")
       
    48 			lim := u.Query().Get("limit")
       
    49 			if since == "" && max == "" {
       
    50 				continue
       
    51 			}
       
    52 			lp = new(LimitParams)
       
    53 			if since != "" {
       
    54 				lp.SinceID, err = strconv.Atoi(since)
       
    55 				if err != nil {
       
    56 					return al, err
       
    57 				}
       
    58 			}
       
    59 			if max != "" {
       
    60 				lp.MaxID, err = strconv.Atoi(max)
       
    61 				if err != nil {
       
    62 					return al, err
       
    63 				}
       
    64 			}
       
    65 			if lim != "" {
       
    66 				lp.Limit, err = strconv.Atoi(lim)
       
    67 				if err != nil {
       
    68 					return al, err
       
    69 				}
       
    70 			}
       
    71 			switch submatch[2] {
       
    72 			case "prev":
       
    73 				al.prev = lp
       
    74 			case "next":
       
    75 				al.next = lp
       
    76 			}
       
    77 		}
       
    78 	}
       
    79 	return al, nil
       
    80 }
    21 
    81 
    22 // restAPI actually does the HTTP query
    82 // restAPI actually does the HTTP query
    23 // It is a copy of rest.API with better handling of parameters with multiple values
    83 // It is a copy of rest.API with better handling of parameters with multiple values
    24 func restAPI(request rest.Request) (*rest.Response, error) {
    84 func restAPI(request rest.Request) (*rest.Response, error) {
    25 	c := &rest.Client{HTTPClient: http.DefaultClient}
    85 	c := &rest.Client{HTTPClient: http.DefaultClient}
   101 	}
   161 	}
   102 	return req, nil
   162 	return req, nil
   103 }
   163 }
   104 
   164 
   105 // apiCall makes a call to the Mastodon API server
   165 // apiCall makes a call to the Mastodon API server
   106 func (mc *Client) apiCall(endPoint string, method rest.Method, params apiCallParams, limitOptions *LimitParams, data interface{}) error {
   166 // If links is not nil, the prev/next links from the API response headers
       
   167 // will be set (if they exist) in the structure.
       
   168 func (mc *Client) apiCall(endPoint string, method rest.Method, params apiCallParams, limitOptions *LimitParams, links *apiLinks, data interface{}) error {
   107 	if mc == nil {
   169 	if mc == nil {
   108 		return fmt.Errorf("use of uninitialized madon client")
   170 		return fmt.Errorf("use of uninitialized madon client")
   109 	}
   171 	}
   110 
   172 
   111 	if limitOptions != nil {
   173 	if limitOptions != nil {
   131 
   193 
   132 	// Make API call
   194 	// Make API call
   133 	r, err := restAPI(req)
   195 	r, err := restAPI(req)
   134 	if err != nil {
   196 	if err != nil {
   135 		return fmt.Errorf("API query (%s) failed: %s", endPoint, err.Error())
   197 		return fmt.Errorf("API query (%s) failed: %s", endPoint, err.Error())
       
   198 	}
       
   199 
       
   200 	if links != nil {
       
   201 		pLinks, err := parseLink(r.Headers["Link"])
       
   202 		if err != nil {
       
   203 			return fmt.Errorf("cannot decode header links (%s): %s", method, err.Error())
       
   204 		}
       
   205 		if pLinks != nil {
       
   206 			*links = *pLinks
       
   207 		}
   136 	}
   208 	}
   137 
   209 
   138 	// Check for error reply
   210 	// Check for error reply
   139 	var errorResult Error
   211 	var errorResult Error
   140 	if err := json.Unmarshal([]byte(r.Body), &errorResult); err == nil {
   212 	if err := json.Unmarshal([]byte(r.Body), &errorResult); err == nil {