Live data from Hacker News

API pagination design

solovyov.net

1–10 of 150 posts

Re: API pagination design

#2
I've worked with APIs (mainly based on ElasticSearch backends) that implement something like this pattern. There, the "cursor" is called a "ScrollId."

Here's what that looks like in ES: https://www.elastic.co/guide/en/elasticsearch/client/java-re...

The APIs I generally work will abstract away most of the scroll context configuration stuff, and just return a page of results, plus the ScrollId for the next page.

Re: API pagination design

#3
Are you a python dev? No, let me guess, rust.

Anyway solving something “basic” languages like php or node solved eons ago is a bit lame and silly. “Cursors” and pagination have been solved way before HN’s lame plebe discovered wanna be “software engineering”. Cool stuff for a f(w)aang(k) worker. Ah yeah ai might help lol?

Re: API pagination design

#4

I've worked with APIs (mainly based on ElasticSearch backends) that implement something like this pattern. There, the "cursor" is called a "ScrollId." Here's what that looks like in ES: https://www.elastic.co/guide/en/elasticsearch/client/java-re... The APIs I generally work will abstract away most of the scroll context configuration stuff, and just return a page of results, plus the ScrollId for the next page.

Elastic search now recommends using “search_after” instead of scrolling for deep pagination, although mechanically they’re pretty similar to use

Re: API pagination design

#5
> One deficiency you can see is that it’s impossible to generate a “previous page” link

It is perfectly possible to have a "previous page" link. Your pagination needs to support "before" cursor semantic, allowing a consumer to retrieve the N items before the row identified by the cursor.

Re: API pagination design

#7
I tried to make cursor based pagination work in a GraphQL API over MySQL and failed. The problem was that it had to work for a very wide range of SQL statements, with arbitrary order clause, where clause and at least one join.

Offset pagination works fine in this scenario. But something like `where id > 42 limit 100` fails with an arbitrary sorting order on non-unique columns. All I could do would be to generate the unpaginated result, then find the cursor within it, and take the limit after that. Which is too inefficient to be practical.

If I missed a decent solution, please tell.

Re: API pagination design

#8
Another reason to use cursors is to avoid the problem of repeated or skipped elements caused by concurrent edits. If you use offsets and you’re on page 10, and someone deletes an item on page 1, the whole list shifts and you can accidentally skip an item on page 11. Likewise if someone adds an item on page 1 and you’re on page 10, one of the page 10 items will also show up on page 11.

Cursors elegantly sidestep these issues.

Re: API pagination design

#10
Cursors are stateful. This greatly complicates the design of the backend.

First, you have to maintain state in some kind of session on the app server.

Second, if you have more than one app server, you'll have to share the sessions across them using Redis or Hazelcast or something.

Third, cursors have to be closed, which means you have to know when the user is done with the result set. This is impossible to know. The user could go to page 2 and then go to lunch. So you have to leave it open for a while, and then have some kind of timeout. Have a lot of users doing the same thing? Memory fills, both on the app server and in the database server.

Fourth, your cursor is going to leave a transaction open, which interferes with updates and all kinds of other things.

Fifth, most users never go to page 2 anyway. They run another search.

Keeping cursors open in a web app is a spectacularly bad idea.

UPDATE -- I am in error. The article does not recommend a normal database cursor. Disregard my comment.

Post reply on HN