Skip to content

Pagination

When making calls to Machinable API Resources, there may be a ton of results to return, depending on your use case. In order to keep response sizes small and more manageable, results are returned as a paginated list.

Take a look at the response of the following list operation to the dogs API Resource in our Pet Demo project:

1
2
curl -X GET \
  https://pet-demo.machinable.io/api/dogs
1
2
3
4
5
6
7
8
9
import requests

url = "https://pet-demo.machinable.io/api/dogs"

headers = {}

response = requests.request("GET", url, headers=headers)

print(response.text)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var data = null;

var xhr = new XMLHttpRequest();

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === 4) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://pet-demo.machinable.io/api/dogs");

xhr.send(data);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {

    url := "https://pet-demo.machinable.io/api/dogs"

    req, _ := http.NewRequest("GET", url, nil)

    res, _ := http.DefaultClient.Do(req)

    defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)

    fmt.Println(res)
    fmt.Println(string(body))
}

Successful response:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
< HTTP/1.1 200 OK

{
  "count": 2,
  "items": [
    {
      "_metadata": {
        "created": 1552323811,
        "creator": "anonymous",
        "creator_type": "anonymous"
      },
      "age": 2,
      "breed": "French Bulldog",
      "id": "5c8694e3a7748bb224833f51",
      "name": "Murphy"
    },
    {
      "_metadata": {
        "created": 1552326051,
        "creator": "anonymous",
        "creator_type": "anonymous"
      },
      "age": 7,
      "breed": "German Shephard",
      "id": "5c869da3a7748bb224833f5c",
      "name": "Max"
    }
  ],
  "links": {
    "self": "https://pet-demo.machinable.io/api/dogs?_limit=10&_offset=0"
  }
}

As you can see, there are 3 keys at the root of the JSON response; count, links, and items.

count is the total count of results for the query. Based on our request, we now know there are a total of 2 dogs in the dogs resource because we are not filtering the data in any way.

links provides context to what URLs we can request to traverse forward or backward through the paginated results.

items contains each object returned for the page we are requesting. The page we are requesting is determined by the query parameters _limit and _offset.

Limit

_limit is a query parameter that can be used to specify how many results you would like to see in a single response payload. If we take a look at our sample request above, we'll see that we are not specifying a limit, so Machinable will default the page size to 10.

If we specify _limit of 1, we will only get the first result of the dogs objects:

1
2
curl -X GET \
  "https://pet-demo.machinable.io/api/dogs?_limit=1"
1
2
3
4
5
6
7
8
9
import requests

url = "https://pet-demo.machinable.io/api/dogs?_limit=1"

headers = {}

response = requests.request("GET", url, headers=headers)

print(response.text)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var data = null;

var xhr = new XMLHttpRequest();

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === 4) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://pet-demo.machinable.io/api/dogs?_limit=1");

xhr.send(data);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {

    url := "https://pet-demo.machinable.io/api/dogs?_limit=1"

    req, _ := http.NewRequest("GET", url, nil)

    res, _ := http.DefaultClient.Do(req)

    defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)

    fmt.Println(res)
    fmt.Println(string(body))
}

Successful response:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
< HTTP/1.1 200 OK

{
  "count": 2,
  "items": [
    {
      "_metadata": {
        "created": 1552323811,
        "creator": "anonymous",
        "creator_type": "anonymous"
      },
      "age": 2,
      "breed": "French Bulldog",
      "id": "5c8694e3a7748bb224833f51",
      "name": "Murphy"
    }
  ],
  "links": {
    "self": "https://pet-demo.machinable.io/api/dogs?_limit=1&_offset=0",
    "next": "https://pet-demo.machinable.io/api/dogs?_limit=1&_offset=1"
  }
}

Info

The _limit query parameter is a reserved field that cannot be used in API Resource data fields.

The _limit query parameter has the following constraints:

Maximum: 100
Minimum: 1
Default: 10

Offset

_offset is a query parameter that can be used to specify how many results to skip before the response payload is built and returned. If we take a look at our sample request above, we'll see that we are not specifying an offset, so Machinable will default the offset to 0, giving us the first page of the results.

If we continue to build off of the request in our example and provide an _offset of 1 with a _limit of 1, we will get the second "page" of results. Since there are only 2 dogs in the resource, the second page will be the last page:

1
2
curl -X GET \
  "https://pet-demo.machinable.io/api/dogs?_limit=1&_offset=1"
1
2
3
4
5
6
7
8
9
import requests

url = "https://pet-demo.machinable.io/api/dogs?_limit=1&_offset=1"

headers = {}

response = requests.request("GET", url, headers=headers)

print(response.text)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var data = null;

var xhr = new XMLHttpRequest();

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === 4) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://pet-demo.machinable.io/api/dogs?_limit=1&_offset=1");

xhr.send(data);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {

    url := "https://pet-demo.machinable.io/api/dogs?_limit=1&_offset=1"

    req, _ := http.NewRequest("GET", url, nil)

    res, _ := http.DefaultClient.Do(req)

    defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)

    fmt.Println(res)
    fmt.Println(string(body))
}

Successful response:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
< HTTP/1.1 200 OK

{
  "count": 2,
  "items": [
    {
      "_metadata": {
        "created": 1552339933,
        "creator": "anonymous",
        "creator_type": "anonymous"
      },
      "age": 7,
      "breed": "German Shephard",
      "id": "5c86d3dda7748bb224833f68",
      "name": "Max"
    }
  ],
  "links": {
    "self": "https://pet-demo.machinable.io/api/dogs?_limit=1&_offset=1",
    "prev": "https://pet-demo.machinable.io/api/dogs?_limit=1&_offset=0"
  }
}

Info

The _offset query parameter is a reserved field that cannot be used in API Resource data fields.

The _offset query parameter has the following constraints:

Minimum: 0
Default: 0

With the use of _limit and _offset we can traverse the entire list of results without having to return all of them in a single request.

The links field provides contextual URLs for the current (self), next, and prev (previous) page of results. This can be helpful when creating a paginated table of data so the table does not have to keep track of which page it is on (limit and offset), only what the next and prev URLs are, which will be returned with each list request.