Quantcast
Channel: ASP.Net Web API – Bit of Technology
Viewing all articles
Browse latest Browse all 37

Building ASP.Net Web API RESTful Service – Part 7

$
0
0

This is the seventh part of Building ASP.Net Web API RESTful Service Series. The topics we’ll cover are:

Implement Resources Pagination

In this post we’ll discuss the different ways to implement results pagination, we’ll implement manual pagination then format the response in two different ways (having pagination meta-data in an envelope, and in pagination header).

It is well known that overwhelming your server with a query which returns hundreds of thousand of records is a bad thing, when we are designing an API, we should consider returning the results of our GET methods in paginated way, i.e. providing 10 results on each request, and giving the API consumer the ability to navigate through results, specify the size of the page,  and which page he wants.

Manual Pagination and Envelopes

We’ll modify the “CoursesController” to use pagination instead of returning the whole courses at once.

Let’s see the code below:


   public Object Get(int page = 0, int pageSize = 10)
        {
            IQueryable<Course> query;

            query = TheRepository.GetAllCourses().OrderBy(c => c.CourseSubject.Id);
            var totalCount = query.Count();
            var totalPages = (int)Math.Ceiling((double)totalCount / pageSize);

            var urlHelper = new UrlHelper(Request);
            var prevLink = page > 0 ? urlHelper.Link("Courses", new { page = page - 1 }) : "";
            var nextLink = page < totalPages - 1 ? urlHelper.Link("Courses", new { page = page + 1 }) : "";

            var results = query
                          .Skip(pageSize * page)
                          .Take(pageSize)
                          .ToList()
                          .Select(s => TheModelFactory.Create(s));

            return new
            {
                TotalCount = totalCount,
                TotalPages = totalPages,
                PrevPageLink = prevLink,
                NextPageLink = nextLink,
                Results = results
            };

        }

What we’ve done here is simple, we’ve introduced the below to “CoursesController”

    • Added two new optional parameters to the GET method with default values, those optional parameters are translated to query string values, i.e. if we want to request the second page of courses our GET request will be on the form: http://localhost:{your_port}/api/courses/?page=1 Notice we didn’t specify the pageSize parameter and it took the default values 10. Sample of response will be on the form below:

{

    "totalCount": 33,
    "totalPages": 4,
    "prevPageLink": "http://localhost:8323/api/courses?page=0&pageSize=10",
    "nextPageLink": "http://localhost:8323/api/courses?page=2&pageSize=10",
    "results": [ /* Array containts the results*/ ]

}

  • The method “GetAllCourses” in our Repository returns “IQueryable” response, which is perfect because till this moment the query is represented in memory and didn’t execute against SQL server, so paging and order by for query are executing correctly.
  • We’re using envelope to wrap our response, this envelope contains pagination meta-data inside the JSON response such as: totalCount, totalPages, prevPageLink, nextPageLink. It is important to return the total records count and total pages so API consumer will be able to bind results and apply pagination on grid easily.

Returning the pagination meta-data in the response body is a common technique, there is nothing wrong about it as everything is visible for the developer, the draw back of this approach is that API consumer will dig into the response to extract data he was originally asking for and maybe ignoring all the pagination meta data we returned if he do not need to use it. So the other cleaner way to return pagination meta-data is to include them in response header, so we’ll keep the response body for the results only and we’ll add new header called “X-Pagination” which contains all pagination meta-data.

Manual Pagination and Pagination Headers

We’ll modify “StudentsController” to use headers to return pagination meta-data, in this approach API consumer can use this header if he is interested in the pagination meta-data, other wise he can just ignore this header and read the results of the query directly from response body.

Applying this is fairly simple, the pagination technique we used in “CoursesControrler” will be used the same here, except for returning the pagination meta-data in new header. Take a look on the code below:


public IEnumerable<StudentBaseModel> Get(int page = 0, int pageSize = 10)
        {
            IQueryable<Student> query;

            query = TheRepository.GetAllStudentsWithEnrollments().OrderBy(c => c.LastName);

            var totalCount = query.Count();
            var totalPages = (int)Math.Ceiling((double)totalCount / pageSize);

            var urlHelper = new UrlHelper(Request);
            var prevLink = page > 0 ? urlHelper.Link("Students", new { page = page - 1, pageSize = pageSize }) : "";
            var nextLink = page < totalPages - 1 ? urlHelper.Link("Students", new { page = page + 1, pageSize = pageSize }) : "";

         var paginationHeader =  new
                                  {
                                      TotalCount = totalCount,
                                      TotalPages = totalPages,
                                      PrevPageLink = prevLink,
                                      NextPageLink = nextLink
                                  };

             System.Web.HttpContext.Current.Response.Headers.Add("X-Pagination",
                                                                 Newtonsoft.Json.JsonConvert.SerializeObject(paginationHeader));

            var results = query
                        .Skip(pageSize * page)
                        .Take(pageSize)
                        .ToList()
                        .Select(s => TheModelFactory.CreateSummary(s));

              return results;
        }

Notice how we added a new header to the response collection headers which contains a serialized JSON object containing all pagination meta-data.

In the next post we’ll talk briefly about web API security and how we can implement Basic authentication.

Source code is available on GitHub.



Viewing all articles
Browse latest Browse all 37

Trending Articles