From d32c4d4ed1c57de93f2a75827f6dfd013bef3c6d Mon Sep 17 00:00:00 2001
From: 178inaba <178inaba@users.noreply.github.com>
Date: Thu, 4 May 2017 21:56:54 +0900
Subject: [PATCH] Add Pagination

---
 accounts.go          |  92 +++++++++++------------
 accounts_test.go     |  29 ++++----
 example_test.go      |   2 +-
 helper.go            |   3 +
 instance.go          |   2 +-
 mastodon.go          | 173 +++++++++++++++++++++++--------------------
 mastodon_test.go     |  50 +------------
 notification.go      |  13 ++--
 notification_test.go |   2 +-
 report.go            |   4 +-
 status.go            |  79 ++++++++++----------
 status_test.go       |  22 +++---
 12 files changed, 217 insertions(+), 254 deletions(-)

diff --git a/accounts.go b/accounts.go
index a52cf9a..01390b8 100644
--- a/accounts.go
+++ b/accounts.go
@@ -30,7 +30,7 @@ type Account struct {
 // GetAccount return Account.
 func (c *Client) GetAccount(ctx context.Context, id int) (*Account, error) {
 	var account Account
-	err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%d", id), nil, &account, nil)
+	_, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%d", id), nil, &account, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -40,7 +40,7 @@ func (c *Client) GetAccount(ctx context.Context, id int) (*Account, error) {
 // GetAccountCurrentUser return Account of current user.
 func (c *Client) GetAccountCurrentUser(ctx context.Context) (*Account, error) {
 	var account Account
-	err := c.doAPI(ctx, http.MethodGet, "/api/v1/accounts/verify_credentials", nil, &account, nil)
+	_, err := c.doAPI(ctx, http.MethodGet, "/api/v1/accounts/verify_credentials", nil, &account, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -76,7 +76,7 @@ func (c *Client) AccountUpdate(ctx context.Context, profile *Profile) (*Account,
 	}
 
 	var account Account
-	err := c.doAPI(ctx, http.MethodPatch, "/api/v1/accounts/update_credentials", params, &account, nil)
+	_, err := c.doAPI(ctx, http.MethodPatch, "/api/v1/accounts/update_credentials", params, &account, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -84,53 +84,43 @@ func (c *Client) AccountUpdate(ctx context.Context, profile *Profile) (*Account,
 }
 
 // GetAccountStatuses return statuses by specified accuont.
-func (c *Client) GetAccountStatuses(ctx context.Context, id int64) ([]*Status, error) {
+func (c *Client) GetAccountStatuses(ctx context.Context, id int64, pg *Pagination) ([]*Status, *Pagination, error) {
 	var statuses []*Status
-	err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%d/statuses", id), nil, &statuses, nil)
+	retPG, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%d/statuses", id), nil, &statuses, pg)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
-	return statuses, nil
+	return statuses, retPG, nil
 }
 
 // GetAccountFollowers return followers list.
-func (c *Client) GetAccountFollowers(ctx context.Context, id int64) ([]*Account, error) {
-	params := url.Values{}
-	var total []*Account
-	for {
-		var accounts []*Account
-		var next bool
-		err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%d/followers", id), params, &accounts, &next)
-		if err != nil {
-			return nil, err
-		}
-		total = append(total, accounts...)
-		if !next {
-			break
-		}
-		time.Sleep(c.interval)
+func (c *Client) GetAccountFollowers(ctx context.Context, id int64, pg *Pagination) ([]*Account, *Pagination, error) {
+	var accounts []*Account
+	retPG, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%d/followers", id), nil, &accounts, pg)
+	if err != nil {
+		return nil, nil, err
 	}
-	return total, nil
+	return accounts, retPG, nil
 }
 
 // GetAccountFollowing return following list.
-func (c *Client) GetAccountFollowing(ctx context.Context, id int64) ([]*Account, error) {
+func (c *Client) GetAccountFollowing(ctx context.Context, id int64, pg *Pagination) ([]*Account, *Pagination, error) {
 	var accounts []*Account
-	err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%d/following", id), nil, &accounts, nil)
+	retPG, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%d/following", id), nil, &accounts, pg)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
-	return accounts, nil
+	return accounts, retPG, nil
 }
 
 // GetBlocks return block list.
-func (c *Client) GetBlocks(ctx context.Context) ([]*Account, error) {
+func (c *Client) GetBlocks(ctx context.Context, pg *Pagination) ([]*Account, *Pagination, error) {
 	var accounts []*Account
-	err := c.doAPI(ctx, http.MethodGet, "/api/v1/blocks", nil, &accounts, nil)
+	retPG, err := c.doAPI(ctx, http.MethodGet, "/api/v1/blocks", nil, &accounts, pg)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
-	return accounts, nil
+	return accounts, retPG, nil
 }
 
 // Relationship hold information for relation-ship to the account.
@@ -146,7 +136,7 @@ type Relationship struct {
 // AccountFollow follow the account.
 func (c *Client) AccountFollow(ctx context.Context, id int64) (*Relationship, error) {
 	var relationship Relationship
-	err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/follow", id), nil, &relationship, nil)
+	_, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/follow", id), nil, &relationship, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -156,7 +146,7 @@ func (c *Client) AccountFollow(ctx context.Context, id int64) (*Relationship, er
 // AccountUnfollow unfollow the account.
 func (c *Client) AccountUnfollow(ctx context.Context, id int64) (*Relationship, error) {
 	var relationship Relationship
-	err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/unfollow", id), nil, &relationship, nil)
+	_, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/unfollow", id), nil, &relationship, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -166,7 +156,7 @@ func (c *Client) AccountUnfollow(ctx context.Context, id int64) (*Relationship,
 // AccountBlock block the account.
 func (c *Client) AccountBlock(ctx context.Context, id int64) (*Relationship, error) {
 	var relationship Relationship
-	err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/block", id), nil, &relationship, nil)
+	_, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/block", id), nil, &relationship, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -176,7 +166,7 @@ func (c *Client) AccountBlock(ctx context.Context, id int64) (*Relationship, err
 // AccountUnblock unblock the account.
 func (c *Client) AccountUnblock(ctx context.Context, id int64) (*Relationship, error) {
 	var relationship Relationship
-	err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/unblock", id), nil, &relationship, nil)
+	_, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/unblock", id), nil, &relationship, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -186,7 +176,7 @@ func (c *Client) AccountUnblock(ctx context.Context, id int64) (*Relationship, e
 // AccountMute mute the account.
 func (c *Client) AccountMute(ctx context.Context, id int64) (*Relationship, error) {
 	var relationship Relationship
-	err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/mute", id), nil, &relationship, nil)
+	_, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/mute", id), nil, &relationship, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -196,7 +186,7 @@ func (c *Client) AccountMute(ctx context.Context, id int64) (*Relationship, erro
 // AccountUnmute unmute the account.
 func (c *Client) AccountUnmute(ctx context.Context, id int64) (*Relationship, error) {
 	var relationship Relationship
-	err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/unmute", id), nil, &relationship, nil)
+	_, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%d/unmute", id), nil, &relationship, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -211,7 +201,7 @@ func (c *Client) GetAccountRelationships(ctx context.Context, ids []int64) ([]*R
 	}
 
 	var relationships []*Relationship
-	err := c.doAPI(ctx, http.MethodGet, "/api/v1/accounts/relationships", params, &relationships, nil)
+	_, err := c.doAPI(ctx, http.MethodGet, "/api/v1/accounts/relationships", params, &relationships, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -225,7 +215,7 @@ func (c *Client) AccountsSearch(ctx context.Context, q string, limit int64) ([]*
 	params.Set("limit", fmt.Sprint(limit))
 
 	var accounts []*Account
-	err := c.doAPI(ctx, http.MethodGet, "/api/v1/accounts/search", params, &accounts, nil)
+	_, err := c.doAPI(ctx, http.MethodGet, "/api/v1/accounts/search", params, &accounts, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -238,7 +228,7 @@ func (c *Client) FollowRemoteUser(ctx context.Context, uri string) (*Account, er
 	params.Set("uri", uri)
 
 	var account Account
-	err := c.doAPI(ctx, http.MethodPost, "/api/v1/follows", params, &account, nil)
+	_, err := c.doAPI(ctx, http.MethodPost, "/api/v1/follows", params, &account, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -246,31 +236,33 @@ func (c *Client) FollowRemoteUser(ctx context.Context, uri string) (*Account, er
 }
 
 // GetFollowRequests return follow-requests.
-func (c *Client) GetFollowRequests(ctx context.Context) ([]*Account, error) {
+func (c *Client) GetFollowRequests(ctx context.Context, pg *Pagination) ([]*Account, *Pagination, error) {
 	var accounts []*Account
-	err := c.doAPI(ctx, http.MethodGet, "/api/v1/follow_requests", nil, &accounts, nil)
+	retPG, err := c.doAPI(ctx, http.MethodGet, "/api/v1/follow_requests", nil, &accounts, pg)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
-	return accounts, nil
+	return accounts, retPG, nil
 }
 
 // FollowRequestAuthorize is authorize the follow request of user with id.
 func (c *Client) FollowRequestAuthorize(ctx context.Context, id int64) error {
-	return c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/follow_requests/%d/authorize", id), nil, nil, nil)
+	_, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/follow_requests/%d/authorize", id), nil, nil, nil)
+	return err
 }
 
 // FollowRequestReject is rejects the follow request of user with id.
 func (c *Client) FollowRequestReject(ctx context.Context, id int64) error {
-	return c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/follow_requests/%d/reject", id), nil, nil, nil)
+	_, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/follow_requests/%d/reject", id), nil, nil, nil)
+	return err
 }
 
 // GetMutes returns the list of users muted by the current user.
-func (c *Client) GetMutes(ctx context.Context) ([]*Account, error) {
+func (c *Client) GetMutes(ctx context.Context, pg *Pagination) ([]*Account, *Pagination, error) {
 	var accounts []*Account
-	err := c.doAPI(ctx, http.MethodGet, "/api/v1/mutes", nil, &accounts, nil)
+	retPG, err := c.doAPI(ctx, http.MethodGet, "/api/v1/mutes", nil, &accounts, pg)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
-	return accounts, nil
+	return accounts, retPG, nil
 }
diff --git a/accounts_test.go b/accounts_test.go
index cc05d1b..f4dc8d6 100644
--- a/accounts_test.go
+++ b/accounts_test.go
@@ -25,11 +25,11 @@ func TestGetAccount(t *testing.T) {
 		ClientSecret: "bar",
 		AccessToken:  "zoo",
 	})
-	a, err := client.GetAccount(context.Background(), 1)
+	_, err := client.GetAccount(context.Background(), 1)
 	if err == nil {
 		t.Fatalf("should be fail: %v", err)
 	}
-	a, err = client.GetAccount(context.Background(), 1234567)
+	a, err := client.GetAccount(context.Background(), 1234567)
 	if err != nil {
 		t.Fatalf("should not be fail: %v", err)
 	}
@@ -113,6 +113,7 @@ func TestGetAccountStatuses(t *testing.T) {
 			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
 			return
 		}
+		//w.Header().Set("Link", `<http://example.com/api/v1/accounts/1234567/statuses?max_id=123>; rel="next", <http://example.com/api/v1/accounts/1234567/statuses?since_id=789>; rel="prev"`)
 		fmt.Fprintln(w, `[{"content": "foo"}, {"content": "bar"}]`)
 		return
 	}))
@@ -124,11 +125,11 @@ func TestGetAccountStatuses(t *testing.T) {
 		ClientSecret: "bar",
 		AccessToken:  "zoo",
 	})
-	_, err := client.GetAccountStatuses(context.Background(), 123)
+	_, _, err := client.GetAccountStatuses(context.Background(), 123, nil)
 	if err == nil {
 		t.Fatalf("should be fail: %v", err)
 	}
-	ss, err := client.GetAccountStatuses(context.Background(), 1234567)
+	ss, _, err := client.GetAccountStatuses(context.Background(), 1234567, nil)
 	if err != nil {
 		t.Fatalf("should not be fail: %v", err)
 	}
@@ -157,11 +158,11 @@ func TestGetAccountFollowers(t *testing.T) {
 		ClientSecret: "bar",
 		AccessToken:  "zoo",
 	})
-	_, err := client.GetAccountFollowers(context.Background(), 123)
+	_, _, err := client.GetAccountFollowers(context.Background(), 123, nil)
 	if err == nil {
 		t.Fatalf("should be fail: %v", err)
 	}
-	fl, err := client.GetAccountFollowers(context.Background(), 1234567)
+	fl, _, err := client.GetAccountFollowers(context.Background(), 1234567, nil)
 	if err != nil {
 		t.Fatalf("should not be fail: %v", err)
 	}
@@ -193,11 +194,11 @@ func TestGetAccountFollowing(t *testing.T) {
 		ClientSecret: "bar",
 		AccessToken:  "zoo",
 	})
-	_, err := client.GetAccountFollowing(context.Background(), 123)
+	_, _, err := client.GetAccountFollowing(context.Background(), 123, nil)
 	if err == nil {
 		t.Fatalf("should be fail: %v", err)
 	}
-	fl, err := client.GetAccountFollowing(context.Background(), 1234567)
+	fl, _, err := client.GetAccountFollowing(context.Background(), 1234567, nil)
 	if err != nil {
 		t.Fatalf("should not be fail: %v", err)
 	}
@@ -231,11 +232,11 @@ func TestGetBlocks(t *testing.T) {
 		ClientSecret: "bar",
 		AccessToken:  "zoo",
 	})
-	_, err := client.GetBlocks(context.Background())
+	_, _, err := client.GetBlocks(context.Background(), nil)
 	if err == nil {
 		t.Fatalf("should be fail: %v", err)
 	}
-	bl, err := client.GetBlocks(context.Background())
+	bl, _, err := client.GetBlocks(context.Background(), nil)
 	if err != nil {
 		t.Fatalf("should not be fail: %v", err)
 	}
@@ -566,11 +567,11 @@ func TestGetFollowRequests(t *testing.T) {
 		ClientSecret: "bar",
 		AccessToken:  "zoo",
 	})
-	_, err := client.GetFollowRequests(context.Background())
+	_, _, err := client.GetFollowRequests(context.Background(), nil)
 	if err == nil {
 		t.Fatalf("should be fail: %v", err)
 	}
-	fReqs, err := client.GetFollowRequests(context.Background())
+	fReqs, _, err := client.GetFollowRequests(context.Background(), nil)
 	if err != nil {
 		t.Fatalf("should not be fail: %v", err)
 	}
@@ -652,11 +653,11 @@ func TestGetMutes(t *testing.T) {
 		ClientSecret: "bar",
 		AccessToken:  "zoo",
 	})
-	_, err := client.GetMutes(context.Background())
+	_, _, err := client.GetMutes(context.Background(), nil)
 	if err == nil {
 		t.Fatalf("should be fail: %v", err)
 	}
-	mutes, err := client.GetMutes(context.Background())
+	mutes, _, err := client.GetMutes(context.Background(), nil)
 	if err != nil {
 		t.Fatalf("should not be fail: %v", err)
 	}
diff --git a/example_test.go b/example_test.go
index 307b6d5..1d85b25 100644
--- a/example_test.go
+++ b/example_test.go
@@ -32,7 +32,7 @@ func ExampleClient() {
 	if err != nil {
 		log.Fatal(err)
 	}
-	timeline, err := c.GetTimelineHome(context.Background())
+	timeline, _, err := c.GetTimelineHome(context.Background(), nil)
 	if err != nil {
 		log.Fatal(err)
 	}
diff --git a/helper.go b/helper.go
index 05af20f..281f5a2 100644
--- a/helper.go
+++ b/helper.go
@@ -37,6 +37,9 @@ func Base64Encode(file *os.File) (string, error) {
 		";base64," + base64.StdEncoding.EncodeToString(d), nil
 }
 
+// Int64 is a helper function to get the pointer value of a int64.
+func Int64(v int64) *int64 { return &v }
+
 // String is a helper function to get the pointer value of a string.
 func String(v string) *string { return &v }
 
diff --git a/instance.go b/instance.go
index 9b45c25..43c455c 100644
--- a/instance.go
+++ b/instance.go
@@ -16,7 +16,7 @@ type Instance struct {
 // GetInstance return Instance.
 func (c *Client) GetInstance(ctx context.Context) (*Instance, error) {
 	var instance Instance
-	err := c.doAPI(ctx, http.MethodGet, "/api/v1/instance", nil, &instance, nil)
+	_, err := c.doAPI(ctx, http.MethodGet, "/api/v1/instance", nil, &instance, nil)
 	if err != nil {
 		return nil, err
 	}
diff --git a/mastodon.go b/mastodon.go
index 16ccb08..b352e32 100644
--- a/mastodon.go
+++ b/mastodon.go
@@ -4,6 +4,8 @@ import (
 	"bytes"
 	"context"
 	"encoding/json"
+	"errors"
+	"fmt"
 	"io"
 	"mime/multipart"
 	"net/http"
@@ -11,8 +13,10 @@ import (
 	"os"
 	"path"
 	"path/filepath"
+	"strconv"
 	"strings"
-	"time"
+
+	"github.com/tomnomnom/linkheader"
 )
 
 // Config is a setting for access mastodon APIs.
@@ -26,64 +30,13 @@ type Config struct {
 // Client is a API client for mastodon.
 type Client struct {
 	http.Client
-	config   *Config
-	interval time.Duration
+	config *Config
 }
 
-type page struct {
-	next string
-}
-
-func linkHeader(h http.Header, rel string) []string {
-	var links []string
-	for _, v := range h["Link"] {
-		var p string
-		for len(v) > 0 {
-			i := strings.Index(v, ";")
-			if i < 0 {
-				break
-			}
-			e := i
-			i++
-			for i < len(v) {
-				if v[i] != ' ' {
-					break
-				}
-				i++
-			}
-			p = strings.TrimSpace(v[i:])
-			if !strings.HasPrefix(p, "rel=") {
-				break
-			}
-			i += 4
-			pos := strings.Index(p[4:], `,`)
-			if pos > 0 {
-				p = p[4 : 4+pos]
-				i += pos
-			} else {
-				p = p[4:]
-				i = len(v) - 1
-			}
-			if k := strings.Trim(p, `"`); k == rel {
-				links = append(links, strings.Trim(v[:e], "<>"))
-			}
-			i++
-			for i < len(v) {
-				if v[i] != ' ' {
-					break
-				}
-				i++
-			}
-			v = v[i:]
-		}
-	}
-	return links
-}
-
-func (c *Client) doAPI(ctx context.Context, method string, uri string, params interface{}, res interface{}, next *bool) error {
+func (c *Client) doAPI(ctx context.Context, method string, uri string, params interface{}, res interface{}, pg *Pagination) (*Pagination, error) {
 	u, err := url.Parse(c.config.Server)
 	if err != nil {
-		return err
+		return nil, err
 	}
 	u.Path = path.Join(u.Path, uri)
 
@@ -92,18 +45,18 @@ func (c *Client) doAPI(ctx context.Context, method string, uri string, params in
 	if values, ok := params.(url.Values); ok {
 		var body io.Reader
 		if method == http.MethodGet {
-			u.RawQuery = values.Encode()
+			u.RawQuery = pg.setValues(values).Encode()
 		} else {
 			body = strings.NewReader(values.Encode())
 		}
 		req, err = http.NewRequest(method, u.String(), body)
 		if err != nil {
-			return err
+			return nil, err
 		}
 	} else if file, ok := params.(string); ok {
 		f, err := os.Open(file)
 		if err != nil {
-			return err
+			return nil, err
 		}
 		defer f.Close()
 
@@ -111,25 +64,25 @@ func (c *Client) doAPI(ctx context.Context, method string, uri string, params in
 		mw := multipart.NewWriter(&buf)
 		part, err := mw.CreateFormFile("file", filepath.Base(file))
 		if err != nil {
-			return err
+			return nil, err
 		}
 		_, err = io.Copy(part, f)
 		if err != nil {
-			return err
+			return nil, err
 		}
 		err = mw.Close()
 		if err != nil {
-			return err
+			return nil, err
 		}
 		req, err = http.NewRequest(method, u.String(), &buf)
 		if err != nil {
-			return err
+			return nil, err
 		}
 		ct = mw.FormDataContentType()
 	} else {
 		req, err = http.NewRequest(method, u.String(), nil)
 		if err != nil {
-			return err
+			return nil, err
 		}
 	}
 	req = req.WithContext(ctx)
@@ -140,37 +93,32 @@ func (c *Client) doAPI(ctx context.Context, method string, uri string, params in
 
 	resp, err := c.Do(req)
 	if err != nil {
-		return err
+		return nil, err
 	}
 	defer resp.Body.Close()
 
-	if next != nil && params != nil {
-		nl := linkHeader(resp.Header, "next")
-		*next = false
-		if len(nl) > 0 {
-			u, err = url.Parse(nl[0])
-			if err == nil {
-				for k, v := range u.Query() {
-					params.(url.Values)[k] = v
-				}
-			}
-			*next = true
+	lh := resp.Header.Get("Link")
+	var retPG *Pagination
+	if lh != "" {
+		retPG, err = newPagination(lh)
+		if err != nil {
+			return nil, err
 		}
 	}
+
 	if resp.StatusCode != http.StatusOK {
-		return parseAPIError("bad request", resp)
+		return nil, parseAPIError("bad request", resp)
 	} else if res == nil {
-		return nil
+		return nil, nil
 	}
-	return json.NewDecoder(resp.Body).Decode(&res)
+	return retPG, json.NewDecoder(resp.Body).Decode(&res)
 }
 
 // NewClient return new mastodon API client.
 func NewClient(config *Config) *Client {
 	return &Client{
-		Client:   *http.DefaultClient,
-		config:   config,
-		interval: 10 * time.Second,
+		Client: *http.DefaultClient,
+		config: config,
 	}
 }
 
@@ -257,3 +205,66 @@ type Results struct {
 	Statuses []*Status  `json:"statuses"`
 	Hashtags []string   `json:"hashtags"`
 }
+
+// Pagination is a struct for specifying the get range.
+type Pagination struct {
+	MaxID   *int64
+	SinceID *int64
+	Limit   *int64
+}
+
+func newPagination(rawlink string) (*Pagination, error) {
+	if rawlink == "" {
+		return nil, errors.New("empty link header")
+	}
+
+	p := &Pagination{}
+	for _, link := range linkheader.Parse(rawlink) {
+		switch link.Rel {
+		case "next":
+			maxID, err := getPaginationID(link.URL, "max_id")
+			if err != nil {
+				return nil, err
+			}
+			p.MaxID = &maxID
+		case "prev":
+			sinceID, err := getPaginationID(link.URL, "since_id")
+			if err != nil {
+				return nil, err
+			}
+			p.SinceID = &sinceID
+		}
+	}
+
+	return p, nil
+}
+
+func getPaginationID(rawurl, key string) (int64, error) {
+	u, err := url.Parse(rawurl)
+	if err != nil {
+		return 0, err
+	}
+
+	id, err := strconv.ParseInt(u.Query().Get(key), 10, 64)
+	if err != nil {
+		return 0, err
+	}
+
+	return id, nil
+}
+
+func (p *Pagination) setValues(params url.Values) url.Values {
+	if p != nil {
+		if p.MaxID != nil {
+			params.Set("max_id", fmt.Sprint(p.MaxID))
+		}
+		if p.SinceID != nil {
+			params.Set("since_id", fmt.Sprint(p.SinceID))
+		}
+		if p.Limit != nil {
+			params.Set("limit", fmt.Sprint(p.Limit))
+		}
+	}
+
+	return params
+}
diff --git a/mastodon_test.go b/mastodon_test.go
index e0bf960..0eb376a 100644
--- a/mastodon_test.go
+++ b/mastodon_test.go
@@ -6,7 +6,6 @@ import (
 	"io"
 	"net/http"
 	"net/http/httptest"
-	"reflect"
 	"testing"
 	"time"
 )
@@ -153,7 +152,7 @@ func TestGetTimelineHome(t *testing.T) {
 		ClientSecret: "bar",
 		AccessToken:  "zoo",
 	})
-	tl, err := client.GetTimelineHome(context.Background())
+	tl, _, err := client.GetTimelineHome(context.Background(), nil)
 	if err != nil {
 		t.Fatalf("should not be fail: %v", err)
 	}
@@ -183,7 +182,7 @@ func TestGetTimelineHomeWithCancel(t *testing.T) {
 	})
 	ctx, cancel := context.WithCancel(context.Background())
 	cancel()
-	_, err := client.GetTimelineHome(ctx)
+	_, _, err := client.GetTimelineHome(ctx, nil)
 	if err == nil {
 		t.Fatalf("should be fail: %v", err)
 	}
@@ -199,48 +198,3 @@ func TestForTheCoverages(t *testing.T) {
 	(*ErrorEvent)(nil).event()
 	_ = (&ErrorEvent{io.EOF}).Error()
 }
-
-func TestLinkHeader(t *testing.T) {
-	tests := []struct {
-		header []string
-		rel    string
-		want   []string
-	}{
-		{
-			header: []string{`<http://example.com/?max_id=3>; rel="foo"`},
-			rel:    "boo",
-			want:   nil,
-		},
-		{
-			header: []string{`<http://example.com/?max_id=3>; rel="foo"`},
-			rel:    "foo",
-			want:   []string{"http://example.com/?max_id=3"},
-		},
-		{
-			header: []string{`<http://example.com/?max_id=3>; rel="foo1"`},
-			rel:    "foo",
-			want:   nil,
-		},
-		{
-			header: []string{`<http://example.com/?max_id=3>; rel="foo", <http://example.com/?max_id=4>; rel="bar"`},
-			rel:    "foo",
-			want:   []string{"http://example.com/?max_id=3"},
-		},
-		{
-			header: []string{`<http://example.com/?max_id=3>; rel="foo", <http://example.com/?max_id=4>; rel="bar"`},
-			rel:    "bar",
-			want:   []string{"http://example.com/?max_id=4"},
-		},
-	}
-
-	for _, test := range tests {
-		h := make(http.Header)
-		for _, he := range test.header {
-			h.Add("Link", he)
-		}
-		got := linkHeader(h, test.rel)
-		if !reflect.DeepEqual(got, test.want) {
-			t.Fatalf("want %v but %v", test.want, got)
-		}
-	}
-}
diff --git a/notification.go b/notification.go
index a25f3f0..5df3485 100644
--- a/notification.go
+++ b/notification.go
@@ -17,19 +17,19 @@ type Notification struct {
 }
 
 // GetNotifications return notifications.
-func (c *Client) GetNotifications(ctx context.Context) ([]*Notification, error) {
+func (c *Client) GetNotifications(ctx context.Context, pg *Pagination) ([]*Notification, *Pagination, error) {
 	var notifications []*Notification
-	err := c.doAPI(ctx, http.MethodGet, "/api/v1/notifications", nil, &notifications, nil)
+	retPG, err := c.doAPI(ctx, http.MethodGet, "/api/v1/notifications", nil, &notifications, pg)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
-	return notifications, nil
+	return notifications, retPG, nil
 }
 
 // GetNotification return notification.
 func (c *Client) GetNotification(ctx context.Context, id int64) (*Notification, error) {
 	var notification Notification
-	err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/notifications/%d", id), nil, &notification, nil)
+	_, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/notifications/%d", id), nil, &notification, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -38,5 +38,6 @@ func (c *Client) GetNotification(ctx context.Context, id int64) (*Notification,
 
 // ClearNotifications clear notifications.
 func (c *Client) ClearNotifications(ctx context.Context) error {
-	return c.doAPI(ctx, http.MethodPost, "/api/v1/notifications/clear", nil, nil, nil)
+	_, err := c.doAPI(ctx, http.MethodPost, "/api/v1/notifications/clear", nil, nil, nil)
+	return err
 }
diff --git a/notification_test.go b/notification_test.go
index 87f0e32..2459b1e 100644
--- a/notification_test.go
+++ b/notification_test.go
@@ -32,7 +32,7 @@ func TestGetNotifications(t *testing.T) {
 		ClientSecret: "bar",
 		AccessToken:  "zoo",
 	})
-	ns, err := client.GetNotifications(context.Background())
+	ns, _, err := client.GetNotifications(context.Background(), nil)
 	if err != nil {
 		t.Fatalf("should not be fail: %v", err)
 	}
diff --git a/report.go b/report.go
index 1e6debf..dd9c461 100644
--- a/report.go
+++ b/report.go
@@ -16,7 +16,7 @@ type Report struct {
 // GetReports return report of the current user.
 func (c *Client) GetReports(ctx context.Context) ([]*Report, error) {
 	var reports []*Report
-	err := c.doAPI(ctx, http.MethodGet, "/api/v1/reports", nil, &reports, nil)
+	_, err := c.doAPI(ctx, http.MethodGet, "/api/v1/reports", nil, &reports, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -32,7 +32,7 @@ func (c *Client) Report(ctx context.Context, accountID int64, ids []int64, comme
 	}
 	params.Set("comment", comment)
 	var report Report
-	err := c.doAPI(ctx, http.MethodPost, "/api/v1/reports", params, &report, nil)
+	_, err := c.doAPI(ctx, http.MethodPost, "/api/v1/reports", params, &report, nil)
 	if err != nil {
 		return nil, err
 	}
diff --git a/status.go b/status.go
index dbbed03..74cec09 100644
--- a/status.go
+++ b/status.go
@@ -48,19 +48,19 @@ type Card struct {
 }
 
 // GetFavourites return the favorite list of the current user.
-func (c *Client) GetFavourites(ctx context.Context) ([]*Status, error) {
+func (c *Client) GetFavourites(ctx context.Context, pg *Pagination) ([]*Status, *Pagination, error) {
 	var statuses []*Status
-	err := c.doAPI(ctx, http.MethodGet, "/api/v1/favourites", nil, &statuses, nil)
+	retPG, err := c.doAPI(ctx, http.MethodGet, "/api/v1/favourites", nil, &statuses, pg)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
-	return statuses, nil
+	return statuses, retPG, nil
 }
 
 // GetStatus return status specified by id.
 func (c *Client) GetStatus(ctx context.Context, id int64) (*Status, error) {
 	var status Status
-	err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%d", id), nil, &status, nil)
+	_, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%d", id), nil, &status, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -70,7 +70,7 @@ func (c *Client) GetStatus(ctx context.Context, id int64) (*Status, error) {
 // GetStatusContext return status specified by id.
 func (c *Client) GetStatusContext(ctx context.Context, id int64) (*Context, error) {
 	var context Context
-	err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%d/context", id), nil, &context, nil)
+	_, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%d/context", id), nil, &context, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -80,7 +80,7 @@ func (c *Client) GetStatusContext(ctx context.Context, id int64) (*Context, erro
 // GetStatusCard return status specified by id.
 func (c *Client) GetStatusCard(ctx context.Context, id int64) (*Card, error) {
 	var card Card
-	err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%d/card", id), nil, &card, nil)
+	_, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%d/card", id), nil, &card, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -88,29 +88,29 @@ func (c *Client) GetStatusCard(ctx context.Context, id int64) (*Card, error) {
 }
 
 // GetRebloggedBy returns the account list of the user who reblogged the toot of id.
-func (c *Client) GetRebloggedBy(ctx context.Context, id int64) ([]*Account, error) {
+func (c *Client) GetRebloggedBy(ctx context.Context, id int64, pg *Pagination) ([]*Account, *Pagination, error) {
 	var accounts []*Account
-	err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%d/reblogged_by", id), nil, &accounts, nil)
+	retPG, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%d/reblogged_by", id), nil, &accounts, pg)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
-	return accounts, nil
+	return accounts, retPG, nil
 }
 
 // GetFavouritedBy returns the account list of the user who liked the toot of id.
-func (c *Client) GetFavouritedBy(ctx context.Context, id int64) ([]*Account, error) {
+func (c *Client) GetFavouritedBy(ctx context.Context, id int64, pg *Pagination) ([]*Account, *Pagination, error) {
 	var accounts []*Account
-	err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%d/favourited_by", id), nil, &accounts, nil)
+	retPG, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/statuses/%d/favourited_by", id), nil, &accounts, pg)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
-	return accounts, nil
+	return accounts, retPG, nil
 }
 
 // Reblog is reblog the toot of id and return status of reblog.
 func (c *Client) Reblog(ctx context.Context, id int64) (*Status, error) {
 	var status Status
-	err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%d/reblog", id), nil, &status, nil)
+	_, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%d/reblog", id), nil, &status, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -120,7 +120,7 @@ func (c *Client) Reblog(ctx context.Context, id int64) (*Status, error) {
 // Unreblog is unreblog the toot of id and return status of the original toot.
 func (c *Client) Unreblog(ctx context.Context, id int64) (*Status, error) {
 	var status Status
-	err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%d/unreblog", id), nil, &status, nil)
+	_, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%d/unreblog", id), nil, &status, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -130,7 +130,7 @@ func (c *Client) Unreblog(ctx context.Context, id int64) (*Status, error) {
 // Favourite is favourite the toot of id and return status of the favourite toot.
 func (c *Client) Favourite(ctx context.Context, id int64) (*Status, error) {
 	var status Status
-	err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%d/favourite", id), nil, &status, nil)
+	_, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%d/favourite", id), nil, &status, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -140,7 +140,7 @@ func (c *Client) Favourite(ctx context.Context, id int64) (*Status, error) {
 // Unfavourite is unfavourite the toot of id and return status of the unfavourite toot.
 func (c *Client) Unfavourite(ctx context.Context, id int64) (*Status, error) {
 	var status Status
-	err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%d/unfavourite", id), nil, &status, nil)
+	_, err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/statuses/%d/unfavourite", id), nil, &status, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -148,48 +148,48 @@ func (c *Client) Unfavourite(ctx context.Context, id int64) (*Status, error) {
 }
 
 // GetTimelineHome return statuses from home timeline.
-func (c *Client) GetTimelineHome(ctx context.Context) ([]*Status, error) {
+func (c *Client) GetTimelineHome(ctx context.Context, pg *Pagination) ([]*Status, *Pagination, error) {
 	var statuses []*Status
-	err := c.doAPI(ctx, http.MethodGet, "/api/v1/timelines/home", nil, &statuses, nil)
+	retPG, err := c.doAPI(ctx, http.MethodGet, "/api/v1/timelines/home", nil, &statuses, pg)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
-	return statuses, nil
+	return statuses, retPG, nil
 }
 
 // GetTimelinePublic return statuses from public timeline.
-func (c *Client) GetTimelinePublic(ctx context.Context, isLocal bool) ([]*Status, error) {
+func (c *Client) GetTimelinePublic(ctx context.Context, isLocal bool, pg *Pagination) ([]*Status, *Pagination, error) {
 	params := url.Values{}
 	if isLocal {
 		params.Set("local", "t")
 	}
 
 	var statuses []*Status
-	err := c.doAPI(ctx, http.MethodGet, "/api/v1/timelines/public", params, &statuses, nil)
+	retPG, err := c.doAPI(ctx, http.MethodGet, "/api/v1/timelines/public", params, &statuses, pg)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
-	return statuses, nil
+	return statuses, retPG, nil
 }
 
 // GetTimelineHashtag return statuses from tagged timeline.
-func (c *Client) GetTimelineHashtag(ctx context.Context, tag string, isLocal bool) ([]*Status, error) {
+func (c *Client) GetTimelineHashtag(ctx context.Context, tag string, isLocal bool, pg *Pagination) ([]*Status, *Pagination, error) {
 	params := url.Values{}
 	if isLocal {
 		params.Set("local", "t")
 	}
 
 	var statuses []*Status
-	err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/timelines/tag/%s", url.PathEscape(tag)), params, &statuses, nil)
+	retPG, err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/timelines/tag/%s", url.PathEscape(tag)), params, &statuses, pg)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
-	return statuses, nil
+	return statuses, retPG, nil
 }
 
 // GetTimelineMedia return statuses from media timeline.
 // NOTE: This is an experimental feature of pawoo.net.
-func (c *Client) GetTimelineMedia(ctx context.Context, isLocal bool) ([]*Status, error) {
+func (c *Client) GetTimelineMedia(ctx context.Context, isLocal bool, pg *Pagination) ([]*Status, *Pagination, error) {
 	params := url.Values{}
 	params.Set("media", "t")
 	if isLocal {
@@ -197,11 +197,11 @@ func (c *Client) GetTimelineMedia(ctx context.Context, isLocal bool) ([]*Status,
 	}
 
 	var statuses []*Status
-	err := c.doAPI(ctx, http.MethodGet, "/api/v1/timelines/public", params, &statuses, nil)
+	retPG, err := c.doAPI(ctx, http.MethodGet, "/api/v1/timelines/public", params, &statuses, pg)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
-	return statuses, nil
+	return statuses, retPG, nil
 }
 
 // PostStatus post the toot.
@@ -227,7 +227,7 @@ func (c *Client) PostStatus(ctx context.Context, toot *Toot) (*Status, error) {
 	}
 
 	var status Status
-	err := c.doAPI(ctx, http.MethodPost, "/api/v1/statuses", params, &status, nil)
+	_, err := c.doAPI(ctx, http.MethodPost, "/api/v1/statuses", params, &status, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -236,7 +236,8 @@ func (c *Client) PostStatus(ctx context.Context, toot *Toot) (*Status, error) {
 
 // DeleteStatus delete the toot.
 func (c *Client) DeleteStatus(ctx context.Context, id int64) error {
-	return c.doAPI(ctx, http.MethodDelete, fmt.Sprintf("/api/v1/statuses/%d", id), nil, nil, nil)
+	_, err := c.doAPI(ctx, http.MethodDelete, fmt.Sprintf("/api/v1/statuses/%d", id), nil, nil, nil)
+	return err
 }
 
 // Search search content with query.
@@ -245,7 +246,7 @@ func (c *Client) Search(ctx context.Context, q string, resolve bool) (*Results,
 	params.Set("q", q)
 	params.Set("resolve", fmt.Sprint(resolve))
 	var results Results
-	err := c.doAPI(ctx, http.MethodGet, "/api/v1/search", params, &results, nil)
+	_, err := c.doAPI(ctx, http.MethodGet, "/api/v1/search", params, &results, nil)
 	if err != nil {
 		return nil, err
 	}
@@ -255,7 +256,7 @@ func (c *Client) Search(ctx context.Context, q string, resolve bool) (*Results,
 // UploadMedia upload a media attachment.
 func (c *Client) UploadMedia(ctx context.Context, file string) (*Attachment, error) {
 	var attachment Attachment
-	err := c.doAPI(ctx, http.MethodPost, "/api/v1/media", file, &attachment, nil)
+	_, err := c.doAPI(ctx, http.MethodPost, "/api/v1/media", file, &attachment, nil)
 	if err != nil {
 		return nil, err
 	}
diff --git a/status_test.go b/status_test.go
index bc4eed6..3e7d7b3 100644
--- a/status_test.go
+++ b/status_test.go
@@ -21,7 +21,7 @@ func TestGetFavourites(t *testing.T) {
 		ClientSecret: "bar",
 		AccessToken:  "zoo",
 	})
-	favs, err := client.GetFavourites(context.Background())
+	favs, _, err := client.GetFavourites(context.Background(), nil)
 	if err != nil {
 		t.Fatalf("should not be fail: %v", err)
 	}
@@ -152,11 +152,11 @@ func TestGetRebloggedBy(t *testing.T) {
 		ClientSecret: "bar",
 		AccessToken:  "zoo",
 	})
-	_, err := client.GetRebloggedBy(context.Background(), 123)
+	_, _, err := client.GetRebloggedBy(context.Background(), 123, nil)
 	if err == nil {
 		t.Fatalf("should be fail: %v", err)
 	}
-	rbs, err := client.GetRebloggedBy(context.Background(), 1234567)
+	rbs, _, err := client.GetRebloggedBy(context.Background(), 1234567, nil)
 	if err != nil {
 		t.Fatalf("should not be fail: %v", err)
 	}
@@ -188,11 +188,11 @@ func TestGetFavouritedBy(t *testing.T) {
 		ClientSecret: "bar",
 		AccessToken:  "zoo",
 	})
-	_, err := client.GetFavouritedBy(context.Background(), 123)
+	_, _, err := client.GetFavouritedBy(context.Background(), 123, nil)
 	if err == nil {
 		t.Fatalf("should be fail: %v", err)
 	}
-	fbs, err := client.GetFavouritedBy(context.Background(), 1234567)
+	fbs, _, err := client.GetFavouritedBy(context.Background(), 1234567, nil)
 	if err != nil {
 		t.Fatalf("should not be fail: %v", err)
 	}
@@ -338,11 +338,11 @@ func TestGetTimelinePublic(t *testing.T) {
 	defer ts.Close()
 
 	client := NewClient(&Config{Server: ts.URL})
-	_, err := client.GetTimelinePublic(context.Background(), false)
+	_, _, err := client.GetTimelinePublic(context.Background(), false, nil)
 	if err == nil {
 		t.Fatalf("should be fail: %v", err)
 	}
-	tl, err := client.GetTimelinePublic(context.Background(), true)
+	tl, _, err := client.GetTimelinePublic(context.Background(), true, nil)
 	if err != nil {
 		t.Fatalf("should not be fail: %v", err)
 	}
@@ -374,11 +374,11 @@ func TestGetTimelineHashtag(t *testing.T) {
 		ClientSecret: "bar",
 		AccessToken:  "zoo",
 	})
-	_, err := client.GetTimelineHashtag(context.Background(), "notfound", false)
+	_, _, err := client.GetTimelineHashtag(context.Background(), "notfound", false, nil)
 	if err == nil {
 		t.Fatalf("should be fail: %v", err)
 	}
-	tags, err := client.GetTimelineHashtag(context.Background(), "zzz", true)
+	tags, _, err := client.GetTimelineHashtag(context.Background(), "zzz", true, nil)
 	if err != nil {
 		t.Fatalf("should not be fail: %v", err)
 	}
@@ -410,11 +410,11 @@ func TestGetTimelineMedia(t *testing.T) {
 		ClientSecret: "bar",
 		AccessToken:  "zoo",
 	})
-	_, err := client.GetTimelineMedia(context.Background(), false)
+	_, _, err := client.GetTimelineMedia(context.Background(), false, nil)
 	if err == nil {
 		t.Fatalf("should be fail: %v", err)
 	}
-	tags, err := client.GetTimelineMedia(context.Background(), true)
+	tags, _, err := client.GetTimelineMedia(context.Background(), true, nil)
 	if err != nil {
 		t.Fatalf("should not be fail: %v", err)
 	}