In this video, Nate explains how to add navigation properties to collection pages to improve discoverability in the API.
- [Instructor] In order for our paged collection responses to truly satisfy the HATEOAS constraint, they should include navigation properties that allow the client to move through the pages by following links between the pages. The PagedCollection Model already includes these navigation properties, we just need to write some code that will automatically populate these links. I'm going to add a static helper method to this class to make this really easy. We'll define a new method that returns a PagedCollection of T called Create.
This will take a link, which is the self link, an array of items, a size, and an instance of PagingOptions. And, this method will simply return a new PagedCollection of T with the Self link set to self Value set to the items, the Size set to size, the Offset set to the pagingOptions Offset. Similar with Limit.
The First link can simply be the self link, the Next link will call a method called GetNextLink, which we need to write. This will take self, size, and pagingOptions as the parameters. And, very similar for the Previous and Last links, we'll call this GetPreviousLink for self, size, and pagingOptions and GetLastLink. All right, so let's write that GetNextLink method first. We'll make this a private static method that returns a Link called GetNextLink and it takes a self Link, a size, and a pagingOptions.
We'll do a couple of sanity checks at the beginning to make sure that pagingOptions is not null. We'll check the Offset as well. Then we'll pull the actual Limit and Offset values from the nullable ints. We'll calculate the NextPage as being the offset plus the limit and a quick check, if the next page is greater than or equal to the size, we'll simply return null because we're at the end of the Collection.
Now we want to create a new set of parameters that we'll use to render the new link. We'll make a new RouteValueDictionary which we need to import from routing. And to instantiate the dictionary, we'll start it off with the existing Route Values that were passed in via self. This ensures that any existing Route Values aren't overwritten by the new ones we want to add. We want to add a value called limit, which is set to limit, and a value called offset, which is the new offset, which is the next page.
So, now we'll create a newLink, which is a Link to a Collection with the RouteName that we were already given and then the new parameters, and we'll simply return this newLink. For the PreviousLink and LastLink methods, I've already copied them into the clipboard. You can get this code in the exercise files folder for this video. The Previous and Last methods are similar to the Next method and include some additional math to make sure the Offset is calculated correctly. Now that we've defined this static helper method, let's go use it over in the Room Controller.
In the GetAllRoomOpeningsAsync method, instead of newing up and returning a paged Collection, we'll call this new method instead. We can say var collection equals PagedCollection of Opening.Create and then pass in the parameters. We'll use the same self link and the openings.Items.ToArray and the TotalSize from openings as well, and the pagingOptions.
Now we can get rid of this code and the rest of it should work exactly the same way. Let's test it out. Now clients should have a smooth experience navigating through the paginated results. If we send a request to the openings route again, and I'll minimize the value property for now, we can see the First, Next, and Last elements in the response. The First item is the same as the href, the Next item includes the next page of results, and the Last item pages all the way to the end of the results.
We can try this out right now. By navigating to the Next link, we can see the last two items in the Collection past the first 25. This wraps up our look at adding pagination to the API. If you want to see my solution, open up the beginning state of the next set of exercise files.
- REST vs. RPC
- Using HTTP methods (aka verbs)
- Returning JSON
- Creating a new API project
- Building a root controller
- Routing to controllers with templates
- Requiring HTTPS for security
- Creating resources and data models
- Returning data and resources from a controller
- Representing links (HREFs)
- Representing collections
- Sorting and searching collections
- Creating forms
- Caching and compression
- Authentication and authorization for RESTful APIs