• No se han encontrado resultados

CAPÍTULO 4. Contexto Regional – Dinámica y Estructura agraria regional

4.1. La caña de azúcar en el estado de São Paulo

Another common pagination method the use of “cursors”, sometimes called “markers”. A cursor is usually a unique identifier, or an offset, so that the API can just request more data.

If there is more data to be found, the API will return that data. If there is not more data, then either an error (404) or an empty collection will be returned.

Empty is not Missing

I personally advise against a 404 because the URL is not tech-nically wrong, there is simply no data to be returned in the collection so an empty collection makes more sense.

To try the same example:

1 {

Pagination 120 This JSON has been returned after requesting the first 12 records. 1-12 were all available and, for the sake of example, were all auto-increment integers. Therefore, in this example, if we would like the content that is after 12, then the records having ID from 13 to 24 would be on the next page.

While this provides a very simplified explanation, generally speaking using IDs is a tricky idea. A specific record can move from one category to another, or could be deactivated, or all sorts of things. You can use IDs, but it is generally considered best practice to use an offset instead.

Using an offset is simple. Regardless of your IDs — auto-incrementing, UUID, etc. — you simply put 12 in there and say “I would like 12 records, with an offset of 12”, instead of saying “I would like records after id=12”.

Obscuring Cursors

Facebook sometimes use cursors to obscure actual IDs, but sometimes use them for “cursor based offsets”. Regardless of what the cursor actually is, your user should never really care, so obfuscating it seems like a good idea.

Facebook Graph API using Cursors

How did Facebook get"NQ="and"MQ=="as values? Well, they are intention-ally odd looking as you are not meant to know what they are. A cursor is an opaque value which you can pass to the pagination system to get more information, so it could be 1, 6, 10, 120332435 or Tuesday and it would not matter.

Don Gilbert2let me know that in the example of Facebook they just Base64 encode their cursors:

2http://dongilbert.net/

Pagination 121

Obfuscating the values is not done for security but, I assume, to avoid people trying to do maths on the values. Ignorance is bliss in this scenario, as somebody doing maths on an offset-based paginated result might end up using the same calculation on a primary key integer. If everything is an opaque cursor or marker then nobody can do that.

Extra Requests = Sadness

This approach is not favoured by some client developers, as they do not like the idea of having to make extra HTTP requests to find out that there is no data. However, this seems like the only realistic way to achieve a performant pagination system for large data. Even with a “pages” system, if there is only one record on the last page and that record (or any other in any page) is removed, then the last page will be empty anyway. Every pagination system needs to respond to an empty collection.

Using Cursors with Fractal

Again this is a rather specific example, but should portray the concept.

1 <?php

7 $current = isset($_GET['cursor']) ? (int) base64_decode($_GET['cursor']) : 0;

8 $per_page = isset($_GET['number']) ? (int) $_GET['number'] : 20;

9

10 $places = Place::findNearbyPlaces($lat, $lon) 11 ->limit($per_page)

12 ->skip($current) 13 ->get();

Pagination 122

14

15 $next = base64_encode((string) ($current + $per_page));

16

17 $cursor = new Cursor($current, $next, $places->count());

18

19 $resource = new Collection($places, new PlaceTransformer);

20 $resource->setCursor($cursor);

This will take the current cursor, use it as an offset, then work out the base64 version and convert it. There is a bit of work to do in this example because the Cursor class is intentionally vague. Instead of using an offset it could be a specific ID and you use it for an SQLWHERE id > Xclause, but better not.

Pagination with the Link Header

TheLinkheader is one not often used, but was introduced inRFC 59883for just this sort of thing.

Example showing GitHub’s use of the Link header in an HTTP response

1 Link: <https://api.github.com/user/repos?page=3&per_page=100>; rel="next", 2 <https://api.github.com/user/repos?page=50&per_page=100>; rel="last"

I have never used this and am dubious. Some argue that pagination is metadata, and metadata should be kept out of the response.

Inserting pagination data into the API response in a'pagination' names-pace is very common and has been my go-to solution for years. I would slot it next to the'data'namespace, and that makes it very easy for clients who a) cannot read those HTTP headers and b) do not know to look there.

That said, using theLinkheader can help you avoid the need to wrap your collections in a namespace at all. This might be something that interests you, as through developing Fractal I ran into many developers who hate using a namespace for their collections.

The final advantage to mention would be that theLinkis standard. Parsing it is going to be 100% the same for each API, and will not expect the client to work out if the link is contained inuri,url,hrefor something else.

3http://tools.ietf.org/html/rfc5988#page-6

Pagination 123 Every API should choose its approach to pagination itself. Using this specific header does not make it “more RESTful” regardless of how many people seem to think that is the case. It just makes it more “HTTPish”

than defining your own pagination metadata.

11. Documentation

11.1 Introduction

Regardless of whether you decide to keep an API private or release it to the general public, documentation is incredibly important.

In the very early stages of development, some API developers will rely solely on a Postman collection (discussed inChapter 8: Debugging) to be a sufficient source of documentation for their API. This may be the case, but as soon as the API is in use by more people than just the one developer with their one collection, this quickly becomes a nightmare.

Even if the API is in use internally, without a single source of regularly updated documentation for your API, you will be answering nonstop questions from anyone using it.

If the API is public then… well, without documentation nobody will use your API at all, which could drastically affect the successes of your com-pany. Integration with services via an API is a very important factor for many companies these days, from startups to huge corporations, so do not go through the trouble of building something amazing only to have it completely ignored due to a lack of documentation.