So since the API really desn't work as you'd expect it to, I am documenting this here at least.
I created a testing board with cards A
, B
, C
, ... , M
so I can test on it.
First, grabbing all cards works as expected.
api.find(:boards, '56af532ae7a74a5fcac32e66').cards.map { |c| [c.name, c.id] }
=> [
["A", "56af53367f15b163c0e345fd"],
["B", "56af533783d4fccc1cce3941"],
["C", "56af533831727db409451c9e"],
["D", "56af53397bf672bb56c7c536"],
["E", "56af5339f5e67cf6bcc7323b"],
["F", "56af533ac0aa02de54ab881a"],
["G", "56af533b212b095266ebb506"],
["H", "56af533e11992f20f375fca1"],
["I", "56af533fc1775129aaa7028b"],
["J", "56af5345f81227a7a1cc3a35"],
["K", "56af5345e36b3d3c45b16967"],
["L", "56af534d964b6c4aa93d4aca"],
["M", "56af534e768610ff67c781ce"]
]
Note: the order of the cards isn't by create time, its by their appearance in the board from left column to right column and from top to bottom.
Okay, time to start paginating. Let's get only the first card, shall we?
board.cards(limit: 1).map { |c| [c.name, c.id] }
=> [["M", "56af534e768610ff67c781ce"]]
Ooops, API returns the last element. Definitely unexpected. Lets play with the after/before next.
Let's grab card before the last one.
board.cards(limit: 1, before: '56af534e768610ff67c781ce').map { |c| [c.name, c.id] }
=> [["L", "56af534d964b6c4aa93d4aca"]]
That works well, L
is before M
.
What happens if we grab a card after the last one, response should be empty, right?
board.cards(limit: 1, after: '56af534e768610ff67c781ce').map { |c| [c.name, c.id] }
=> [["M", "56af534e768610ff67c781ce"]]
Mmmm, what? What happens if I grab two card then?
board.cards(limit: 2, after: '56af534e768610ff67c781ce').map { |c| [c.name, c.id] }
=> [
["L", "56af534d964b6c4aa93d4aca"],
["M", "56af534e768610ff67c781ce"]
]
This defies any logic. Definitely can't go through the list from start to finish then, because there is no end to the card list.
We'll have to go through the cards in reverse order in that case. Just specifying limit
works, since by default we're going in reverse order. (which makes total sense, right?)
api.find(:boards, '56af532ae7a74a5fcac32e66').cards(limit: 5).map { |c| [c.name, c.id] }
=> [
["I", "56af533fc1775129aaa7028b"],
["J", "56af5345f81227a7a1cc3a35"],
["K", "56af5345e36b3d3c45b16967"],
["L", "56af534d964b6c4aa93d4aca"],
["M", "56af534e768610ff67c781ce"]
]
Don't let the order of these items fool you! Its still the order how they appear in the board, they're not sorted by the time of creation. If I move M
card in its column so that it is right over L
, the API will return them in reverse order.
The question is now, how to grab the older card from the list? As the other answer says, the IDs are timestamp, so we just sort by the ID and pick the lowest one and continue paginating.
Note: If you're fast, you can create multiple cards during the same second, so the IDs may not in the right order as they just use the number of seconds, not microseconds. That doesn't prevent us from paginating though.
board.cards(limit: 5, before: '56af533fc1775129aaa7028b').map { |c| [c.name, c.id] }
=> [
["D", "56af53397bf672bb56c7c536"],
["E", "56af5339f5e67cf6bcc7323b"],
["F", "56af533ac0aa02de54ab881a"],
["G", "56af533b212b095266ebb506"],
["H", "56af533e11992f20f375fca1"]
]
Awesome, we're getting the next page, let's get the last one.
board.cards(limit: 5, before: '56af53397bf672bb56c7c536').map { |c| [c.name, c.id] }
=> [
["A", "56af53367f15b163c0e345fd"],
["B", "56af533783d4fccc1cce3941"],
["C", "56af533831727db409451c9e"]
]
Yesss, so the last page contains less cards, than the limit, so we know its the last page. Horray!
This is really helpful. I was struggling with proper pagination and the API is poorly documented for this case.
I think there's one mistake in your algorithm that didn't show up because your card's visual order probably corresponds to your creation order. I also created a board called A, B, C, ... and this was working but when I reversed the order with the existing cards I saw it was all out of whack.
Here's how I did it.