Pagination and sorting with Spray directives
List is probably most common element on web pages, sometimes it’s simple ordered list, sometimes more advanced list displayed as table but almost always it has ability to sort list and switch between pages of list. Since Spray.io does not have such abilities we need to write them on Our own.
First of all, how API call for list of elements should look like. I was thinking about using Post message with page number and number of elements per page but then user will not be able to send link to friend with specific page of my list so the best way was to use Get request. For best API practices I used blog entry http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api, and now I’ve got two requirements
- Page and sort should use Get request
- If I call Get without parameters I should be able to get 1 page with first 20 entries sorted by default value
Best way to implement pagination and sorting is to create custom directives that will extend Spray routing dsl.
For pagination we need two parameters, page that we want to get and number of elements per page, so directive will look like:
- Paginate is case class that will hold needed parameters
- PaginDirective is our directive that will extract parameters from URL
- def paginate is function that creates Paginate object from extracted parameters
- private val readPaginatorParams is our extractor, its reads URL params and returns Directive with specific parameters.
Our extractor use parameters directive from Spray and is defined as parameters(‘actualPage.as[Int].?, ‘elementsPerPage.as[Int].?)
You can translate this page as read parameters actualPage as Int and elementsPerPage as Int and if they are not here return None.
I used Option here because user can call our API without parameters (eg. he does not know what parameters he should send) and We shouldn’t send list of all our elements in this case.
Sorting directive looks same as Paging except that we need only one parameter called sortBy that should have values name for sorting by name ASC, and -name for sorting DESC.
As You can see Spray is searching for sortBy parameter in URL, if it’s present then we check if it is sorting ascending or descending (- sign).
It’s time to join those two
We have sorting and paging ready and now we can used them in our API like this:
Works ok but does not looks great, we need sorting and pagination for all lists and this add two more directives. Because we are lazy we can join those two directives into one. Just create custom directive like this:
Now we can use our new directives in more compact form:
Now if user call our API without parameters our page and sort variables will have default values so we will return first page of users list with 20 elements.
If user sends request with elementsPerPage only then he will get first page of our list, same when he will sends only actualPage parameter.
Vinay Sahni about best practices for API designing: http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api