Learn how to add pagination to large collections. In this video, explore how to build paging logic that you can reuse in any collection response.
- [Instructor] If you check out the exercise files for this video, you'll see a few things that I added. I've added some models that represent a booking and an opening in the hotel and their corresponding database entities. I also added services for dealing with these new bookings and openings and a couple of new routes, as well. If you're following along in your own project, you can compare and copy these files from the begin state of this video or it might be easier just to open up the solution in the begin state and keep working from there. One of the new routes that I added demonstrates a problem that the API currently has with returning collections.
I'll show you what I mean in Postman. If I request the slash rooms slash openings route, I get a list of all the openings in the hotel. The problem is that this list is massive. Let's add some Pagination function to the API that we can reuse for any collection like this that returns a lot of items. We'll start by adding a class that extends the base collection class. Create that here in Models called Paged Collection of T and this extends Collection of T.
This Page Collection class will add a number of extra properties to Collection of T. We'll add a nullable int offset. This represents the offset that we're currently at from the beginning of the collection, if any. Add another int called Limit. This represents how many items to return in this one page, if any. We'll return a int called Size which is always there, it's not nullable. And, then, we'll add a number of links.
We'll add a link called First. We'll add a link called Previous. One called Next and one called Last. I'll use JSON.net to control how these are serialized. Say JSON property null value handling. If this one is null, we just want it to be ignored and not added to the output.
I'll do that for Limit, as well, and all the other links. Over on the Rooms controller, the Get All Room Openings route handles that slash room slash openings endpoint. It needs to be able to accept two new parameters for paging; offset and limit. You could add those parameters right here on the Method Signature or we could, instead, create a simple model that holds these values and let ASP.net core automatically bind them for us.
Let's create a model here called Paging Options. Paging Options will have two nullable ends; offset and limit. We can use data annotations to say how these should be validated. I'll import this from the data annotations name space and I'll say that this needs to be between one and some big number and if it's not, the error message will automatically come back as "offset must be greater than zero" in case someone adds a negative value or a zero here.
For Limit, we'll say that the valid range is one to 100 and the error message is "limit must be greater than zero "and less than 100." Now, back in Rooms Controller, let's update this method. This now takes a paging options as a parameter and it may not be there, it may be null. We need to tell ASP.net core that this is coming from the query string, so we'll say From Query and we'll pass this through to the Opening service.
Let's go update the Opening service method signature in I opening service. Say that this accepts a paging options called Paging Options, and in the default implementation here, this also accepts a paging options. All the way at the bottom of this Get Openings async method, instead of return all openings, I'm going to say paged openings is equal to all openings dot skip and we'll skip the offset value and we'll take only the limit value.
Then we'll return paged openings. We need to add one more thing. The paged collection model includes the size property which should reflect the total size of a collection. Let's create another small class that we can pass around internally that holds the size and the values in a particular paged result. We'll create this in the models folder and we'll call this one Paged Results of T.
This will simply have an I numerable of T, called Items, and an int called Total Size. Over in the default opening service, I'm gonna update the signature here to no longer return I numerable but return page results of opening and at the bottom, I'll say, new paged results of opening where the items come from paged openings but the total size comes from all openings dot count.
Now, of course, we need to go update the I opening service signature in the interface. This is paging... Paged results and back to the rooms controller. Now, VAR openings is a paged results of opening. Let's return a paged collection instead of a collection. We still have a self. The value is now openings dot items dot to array. Size is equal to openings dot total size and will reflect back to the caller, the paging options offset and the paging options limit.
There's a few more properties on paged collection that we can set but let's test out what we have so far. Over in Postman, I'll go ahead and update this URL and say limit equals five, offset equals 10. Now we get a response with only five items; that's one, two, three, four, and five, and these are offset 10 from the beginning of the collection. There's one more problem that we need to fix here.
If one of these new parameters is omitted, we get a big exception. That's because we're trying to access the value of a nullable int that is null in this case. We'll add some paging defaults next.
- What is RESTful design?
- Building a new API with ASP.NET Core
- Using HTTP methods
- Returning JSON
- Creating RESTful routing with templates
- Securing RESTful APIs with HTTPS
- Representing resources
- Representing links
- Representing collections
- Sorting and searching collections
- Building forms
- Adding caching to an ASP.NET Core API
- Configuring user authentication and authorization