How does Siesta handle paginated URLs? Is there a mechanism to manage multiple pages of results as a single resource?
Siesta doesn’t provide any special handling for pagination. Paginated URLs behave just like any others: every URL is a unique resource. Siesta does not have any dark magic to merge responses from different URLs into a single resource.
In other words, if your pagination scheme looks like /dingbats?page=3&per_page=10
, then Siesta considers “page 3 of dingbats with 10 per page” to be a single resource. If your pagination scheme looks like /dingbats?since_serial_num=31415&max=20
, then Siesta will have one resource for “up to 20 dingbats since serial number 31415.”
What does this mean in practice? Suppose, for example, that your API returns an X-Next-Page
header (a simplified flavor of Github’s pagination scheme), and you want to merge the results into a single infinitely scrollable table view.
You might do something like this:
private var firstPageOfDingbats: Resource?
private var dingbats: [Dingbat] = []
private var dingbatsDisplayed: Int = 1
func resourceChanged(resource: Resource, event: ResourceEvent) {
refreshPages()
}
func refreshPages() {
// Naive implementation reconstructs the entire dingats array
// with each update — which is probably just fine, since array
// concatenation is cheap.
dingbats.removeAll()
var nextPage = firstPageOfDingbats
while let curPage = nextPage {
// This is a noop if data is up to date, but triggers a
// that runs down the list if it needs updating.
curPage.loadIfNeeded()
// Assuming you’ve set up a content transformer to parse
// the response as [Dingbat], you can pull them out of
// the Resource cheaply.
dingbats.appendContentsOf(
curPage.contentAsType(ifNone: [Dingbat]()))
// Don’t fetch everything if we’ve covered as far as the
// user has scrolled.
if dingbats.count >= dingbatsDisplayed {
break
}
// If we have data and there’s another page, keep going!
nextPage = curPage.optionalRelative(
curPage.latestData?.header("X-Next-Page"))
}
tableView.reloadData()
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dingbats.count
}
// etc.
// Add code to increase dingbatsDisplayed and call refreshPages()
// when user scrolls to the bottom
Siesta’s caching makes this naive traversal of the pages run very fast if there’s already data present and everything is up to date, but will trigger a cascade of updates when things get out of date.
If you know, for example, that old entries will never change and new entries will only appear at the top, you could do a more intelligent array update. This depends on the particular API you’re using and the guarantees it makes.
If you have a sophisticated update scheme and want fine-grained control over exactly what’s requested and how results are held in memory, then you may want to bypass Siesta’s resource caching altogether. You don’t need to abandon Siesta to do that, however! To fall back to a more traditional request-based approach, use the Resource.request(…)
methods instead of load()
and loadIfNeeded()
:
paginatedResource.request(.GET).success { newData in … }
This lets you manage paginatedResource
requests yourself, while still using Siesta’s caching for other parts of the API.