Add support for limits and paging ({since,max}_id) API parameters
authorMikael Berthe <mikael@lilotux.net>
Fri, 28 Apr 2017 15:43:11 +0200
changeset 149 5f922977d7c7
parent 148 ae2cbcf18b55
child 150 cd328b30af77
Add support for limits and paging ({since,max}_id) API parameters
account.go
api.go
app.go
favourites.go
instance.go
madon.go
notifications.go
report.go
search.go
status.go
timelines.go
--- a/account.go	Fri Apr 28 13:28:16 2017 +0200
+++ b/account.go	Fri Apr 28 15:43:11 2017 +0200
@@ -25,9 +25,10 @@
 	// The ID is used for most commands
 	ID int
 
-	// The following fields are used when searching for accounts
-	Q     string
-	Limit int
+	// The Q field (query) is used when searching for accounts
+	Q string
+
+	Limit *LimitParams
 }
 
 // getSingleAccount returns an account entity
@@ -58,7 +59,7 @@
 	}
 
 	var account Account
-	if err := mc.apiCall(endPoint, method, nil, &account); err != nil {
+	if err := mc.apiCall(endPoint, method, nil, nil, &account); err != nil {
 		return nil, err
 	}
 	return &account, nil
@@ -70,6 +71,11 @@
 // The id is optional and depends on the operation.
 func (mc *Client) getMultipleAccounts(op string, opts *getAccountsOptions) ([]Account, error) {
 	var endPoint string
+	var lopt *LimitParams
+
+	if opts != nil {
+		lopt = opts.Limit
+	}
 
 	switch op {
 	case "followers", "following":
@@ -92,13 +98,10 @@
 	params := make(apiCallParams)
 	if op == "search" {
 		params["q"] = opts.Q
-		if opts.Limit > 0 {
-			params["limit"] = strconv.Itoa(opts.Limit)
-		}
 	}
 
 	var accounts []Account
-	if err := mc.apiCall(endPoint, rest.Get, params, &accounts); err != nil {
+	if err := mc.apiCall(endPoint, rest.Get, params, lopt, &accounts); err != nil {
 		return nil, err
 	}
 	return accounts, nil
@@ -131,13 +134,13 @@
 }
 
 // GetAccountFollowers returns the list of accounts following a given account
-func (mc *Client) GetAccountFollowers(accountID int) ([]Account, error) {
+func (mc *Client) GetAccountFollowers(accountID int, lopt *LimitParams) ([]Account, error) {
 	o := &getAccountsOptions{ID: accountID}
 	return mc.getMultipleAccounts("followers", o)
 }
 
 // GetAccountFollowing returns the list of accounts a given account is following
-func (mc *Client) GetAccountFollowing(accountID int) ([]Account, error) {
+func (mc *Client) GetAccountFollowing(accountID int, lopt *LimitParams) ([]Account, error) {
 	o := &getAccountsOptions{ID: accountID}
 	return mc.getMultipleAccounts("following", o)
 }
@@ -177,7 +180,7 @@
 	params["uri"] = uri
 
 	var account Account
-	if err := mc.apiCall("follows", rest.Post, params, &account); err != nil {
+	if err := mc.apiCall("follows", rest.Post, params, nil, &account); err != nil {
 		return nil, err
 	}
 	if account.ID == 0 {
@@ -235,24 +238,24 @@
 }
 
 // SearchAccounts returns a list of accounts matching the query string
-// The limit parameter is optional (can be 0).
-func (mc *Client) SearchAccounts(query string, limit int) ([]Account, error) {
-	o := &getAccountsOptions{Q: query, Limit: limit}
+// The lopt parameter is optional (can be nil) or can be used to set a limit.
+func (mc *Client) SearchAccounts(query string, lopt *LimitParams) ([]Account, error) {
+	o := &getAccountsOptions{Q: query, Limit: lopt}
 	return mc.getMultipleAccounts("search", o)
 }
 
 // GetBlockedAccounts returns the list of blocked accounts
-func (mc *Client) GetBlockedAccounts() ([]Account, error) {
+func (mc *Client) GetBlockedAccounts(lopt *LimitParams) ([]Account, error) {
 	return mc.getMultipleAccounts("blocks", nil)
 }
 
 // GetMutedAccounts returns the list of muted accounts
-func (mc *Client) GetMutedAccounts() ([]Account, error) {
+func (mc *Client) GetMutedAccounts(lopt *LimitParams) ([]Account, error) {
 	return mc.getMultipleAccounts("mutes", nil)
 }
 
 // GetAccountFollowRequests returns the list of follow requests accounts
-func (mc *Client) GetAccountFollowRequests() ([]Account, error) {
+func (mc *Client) GetAccountFollowRequests(lopt *LimitParams) ([]Account, error) {
 	return mc.getMultipleAccounts("follow_requests", nil)
 }
 
@@ -272,7 +275,7 @@
 	}
 
 	var rl []Relationship
-	if err := mc.apiCall("accounts/relationships", rest.Get, params, &rl); err != nil {
+	if err := mc.apiCall("accounts/relationships", rest.Get, params, nil, &rl); err != nil {
 		return nil, err
 	}
 	return rl, nil
@@ -281,7 +284,7 @@
 // GetAccountStatuses returns a list of status entities for the given account
 // If onlyMedia is true, returns only statuses that have media attachments.
 // If excludeReplies is true, skip statuses that reply to other statuses.
-func (mc *Client) GetAccountStatuses(accountID int, onlyMedia, excludeReplies bool) ([]Status, error) {
+func (mc *Client) GetAccountStatuses(accountID int, onlyMedia, excludeReplies bool, lopt *LimitParams) ([]Status, error) {
 	if accountID < 1 {
 		return nil, ErrInvalidID
 	}
@@ -296,7 +299,7 @@
 	}
 
 	var sl []Status
-	if err := mc.apiCall(endPoint, rest.Get, params, &sl); err != nil {
+	if err := mc.apiCall(endPoint, rest.Get, params, lopt, &sl); err != nil {
 		return nil, err
 	}
 	return sl, nil
--- a/api.go	Fri Apr 28 13:28:16 2017 +0200
+++ b/api.go	Fri Apr 28 15:43:11 2017 +0200
@@ -13,6 +13,7 @@
 	"fmt"
 	"net/http"
 	"net/url"
+	"strconv"
 	"strings"
 
 	"github.com/sendgrid/rest"
@@ -102,11 +103,26 @@
 }
 
 // apiCall makes a call to the Mastodon API server
-func (mc *Client) apiCall(endPoint string, method rest.Method, params apiCallParams, data interface{}) error {
+func (mc *Client) apiCall(endPoint string, method rest.Method, params apiCallParams, limitOptions *LimitParams, data interface{}) error {
 	if mc == nil {
 		return fmt.Errorf("use of uninitialized madon client")
 	}
 
+	if limitOptions != nil {
+		if params == nil {
+			params = make(apiCallParams)
+			if limitOptions.Limit > 0 {
+				params["limit"] = strconv.Itoa(limitOptions.Limit)
+			}
+			if limitOptions.SinceID > 0 {
+				params["since_id"] = strconv.Itoa(limitOptions.SinceID)
+			}
+			if limitOptions.MaxID > 0 {
+				params["max_id"] = strconv.Itoa(limitOptions.MaxID)
+			}
+		}
+	}
+
 	// Prepare query
 	req, err := mc.prepareRequest(endPoint, method, params)
 	if err != nil {
--- a/app.go	Fri Apr 28 13:28:16 2017 +0200
+++ b/app.go	Fri Apr 28 15:43:11 2017 +0200
@@ -68,7 +68,7 @@
 	}
 
 	var app registerApp
-	if err := mc.apiCall("apps", rest.Post, params, &app); err != nil {
+	if err := mc.apiCall("apps", rest.Post, params, nil, &app); err != nil {
 		return nil, err
 	}
 
--- a/favourites.go	Fri Apr 28 13:28:16 2017 +0200
+++ b/favourites.go	Fri Apr 28 15:43:11 2017 +0200
@@ -11,9 +11,9 @@
 )
 
 // GetFavourites returns the list of the user's favourites
-func (mc *Client) GetFavourites() ([]Status, error) {
+func (mc *Client) GetFavourites(lopt *LimitParams) ([]Status, error) {
 	var faves []Status
-	err := mc.apiCall("favourites", rest.Get, nil, &faves)
+	err := mc.apiCall("favourites", rest.Get, nil, lopt, &faves)
 	if err != nil {
 		return nil, err
 	}
--- a/instance.go	Fri Apr 28 13:28:16 2017 +0200
+++ b/instance.go	Fri Apr 28 15:43:11 2017 +0200
@@ -13,7 +13,7 @@
 // GetCurrentInstance returns current instance information
 func (mc *Client) GetCurrentInstance() (*Instance, error) {
 	var i Instance
-	if err := mc.apiCall("instance", rest.Get, nil, &i); err != nil {
+	if err := mc.apiCall("instance", rest.Get, nil, nil, &i); err != nil {
 		return nil, err
 	}
 	return &i, nil
--- a/madon.go	Fri Apr 28 13:28:16 2017 +0200
+++ b/madon.go	Fri Apr 28 15:43:11 2017 +0200
@@ -11,6 +11,11 @@
 	"errors"
 )
 
+// LimitParams contains common limit/paging options for the Mastodon REST API
+type LimitParams struct {
+	SinceID, MaxID, Limit int
+}
+
 // apiCallParams is a map with the parameters for an API call
 type apiCallParams map[string]string
 
--- a/notifications.go	Fri Apr 28 13:28:16 2017 +0200
+++ b/notifications.go	Fri Apr 28 15:43:11 2017 +0200
@@ -13,9 +13,9 @@
 )
 
 // GetNotifications returns the list of the user's notifications
-func (mc *Client) GetNotifications() ([]Notification, error) {
+func (mc *Client) GetNotifications(lopt *LimitParams) ([]Notification, error) {
 	var notifications []Notification
-	if err := mc.apiCall("notifications", rest.Get, nil, &notifications); err != nil {
+	if err := mc.apiCall("notifications", rest.Get, nil, lopt, &notifications); err != nil {
 		return nil, err
 	}
 	return notifications, nil
@@ -31,7 +31,7 @@
 
 	var endPoint = "notifications/" + strconv.Itoa(notificationID)
 	var notification Notification
-	if err := mc.apiCall(endPoint, rest.Get, nil, &notification); err != nil {
+	if err := mc.apiCall(endPoint, rest.Get, nil, nil, &notification); err != nil {
 		return nil, err
 	}
 	if notification.ID == 0 {
@@ -48,11 +48,11 @@
 
 	endPoint := "notifications/dismiss"
 	params := apiCallParams{"id": strconv.Itoa(notificationID)}
-	return mc.apiCall(endPoint, rest.Post, params, &Notification{})
+	return mc.apiCall(endPoint, rest.Post, params, nil, &Notification{})
 }
 
 // ClearNotifications deletes all notifications from the Mastodon server for
 // the authenticated user
 func (mc *Client) ClearNotifications() error {
-	return mc.apiCall("notifications/clear", rest.Post, nil, &Notification{})
+	return mc.apiCall("notifications/clear", rest.Post, nil, nil, &Notification{})
 }
--- a/report.go	Fri Apr 28 13:28:16 2017 +0200
+++ b/report.go	Fri Apr 28 15:43:11 2017 +0200
@@ -14,9 +14,9 @@
 )
 
 // GetReports returns the current user's reports
-func (mc *Client) GetReports() ([]Report, error) {
+func (mc *Client) GetReports(lopt *LimitParams) ([]Report, error) {
 	var reports []Report
-	if err := mc.apiCall("reports", rest.Get, nil, &reports); err != nil {
+	if err := mc.apiCall("reports", rest.Get, nil, lopt, &reports); err != nil {
 		return nil, err
 	}
 	return reports, nil
@@ -40,7 +40,7 @@
 	}
 
 	var report Report
-	if err := mc.apiCall("reports", rest.Post, params, &report); err != nil {
+	if err := mc.apiCall("reports", rest.Post, params, nil, &report); err != nil {
 		return nil, err
 	}
 	return &report, nil
--- a/search.go	Fri Apr 28 13:28:16 2017 +0200
+++ b/search.go	Fri Apr 28 15:43:11 2017 +0200
@@ -23,7 +23,7 @@
 	}
 
 	var results Results
-	if err := mc.apiCall("search", rest.Get, params, &results); err != nil {
+	if err := mc.apiCall("search", rest.Get, params, nil, &results); err != nil {
 		return nil, err
 	}
 	return &results, nil
--- a/status.go	Fri Apr 28 13:28:16 2017 +0200
+++ b/status.go	Fri Apr 28 15:43:11 2017 +0200
@@ -48,7 +48,7 @@
 		endPoint += "/" + op
 	}
 
-	return mc.apiCall(endPoint, rest.Get, nil, data)
+	return mc.apiCall(endPoint, rest.Get, nil, nil, data)
 }
 
 // updateStatusData updates the statuses
@@ -114,7 +114,7 @@
 		}
 	}
 
-	return mc.apiCall(endPoint, method, params, data)
+	return mc.apiCall(endPoint, method, params, nil, data)
 }
 
 // GetStatus returns a status
@@ -151,14 +151,14 @@
 }
 
 // GetStatusRebloggedBy returns a list of the accounts who reblogged a status
-func (mc *Client) GetStatusRebloggedBy(statusID int) ([]Account, error) {
+func (mc *Client) GetStatusRebloggedBy(statusID int, lopt *LimitParams) ([]Account, error) {
 	var accounts []Account
 	err := mc.queryStatusData(statusID, "reblogged_by", &accounts)
 	return accounts, err
 }
 
 // GetStatusFavouritedBy returns a list of the accounts who favourited a status
-func (mc *Client) GetStatusFavouritedBy(statusID int) ([]Account, error) {
+func (mc *Client) GetStatusFavouritedBy(statusID int, lopt *LimitParams) ([]Account, error) {
 	var accounts []Account
 	err := mc.queryStatusData(statusID, "favourited_by", &accounts)
 	return accounts, err
--- a/timelines.go	Fri Apr 28 13:28:16 2017 +0200
+++ b/timelines.go	Fri Apr 28 15:43:11 2017 +0200
@@ -17,7 +17,7 @@
 // timeline can be "home", "public", or a hashtag (use ":hashtag" or "#hashtag")
 // For the public timelines, you can set 'local' to true to get only the
 // local instance.
-func (mc *Client) GetTimelines(timeline string, local bool) ([]Status, error) {
+func (mc *Client) GetTimelines(timeline string, local bool, lopt *LimitParams) ([]Status, error) {
 	var endPoint string
 
 	switch {
@@ -39,7 +39,7 @@
 	}
 
 	var tl []Status
-	if err := mc.apiCall(endPoint, rest.Get, params, &tl); err != nil {
+	if err := mc.apiCall(endPoint, rest.Get, params, lopt, &tl); err != nil {
 		return nil, err
 	}
 	return tl, nil