asp.net-web-apipaginationfiltering

How to efficiency filter result set in a RestApi with ASP.net Core


I'm currently revamping an old API we have been using in our companies for years. I have a particular endpoints call GetBookings accepting a massive amount of parameters:

public HttpResponseMessage GetBookings(string contactId, string timeFilter = "upcoming", string bookedBy = null, string resourceTypeIds = null, string clientId = null (...), int pageSize = 25, int pageIndex = 0)
{
   (...)
}

Adding all these parameters doesn't feel nature and I was looking for an alternate way of doing that kind of things.

1/ I studied OData which seems to offer some advance filtering/paging options.

It seems the OData Microsoft version is not up to date (or not maintained?)

2/ I could also just add an endpoint under bookings called search (HttpPost) and accepting a JSON filter.

This approach is NOT really restful and causes some cache issues (as HttpPost requests are not cached).

3/ I could also add a parameter called query to my get bookings endpoint. This query would contain my filter like 'StartDate >=... AND ....'.

This approach seems complicated to implement as I would need to actually parse the query to convert to a lambda expression. I could also use dapper but then it would be vulnerable to SQL Injection.

4/ The last option I found would be to actually create an endpoint accepting of the necessary parameters.

It's easy to implement but kind of ugly?!

How would you implement filtering/paging in your ASP.NET core WebApi?


Solution

  • I've not tried this in .net core, but for webapi I would create a "criteria" or "parameters" object which contains the properties which may be set from the URL.

    e.g.

    public class BookingSearchParameters
    {
        public string contactId { get; set; }
    
        public string timeFilter { get; set; }
    
        etc..
    }
    

    Then I would make the method take that object as a parameter.

    [HttpGet()]
    public HttpResponseMessage GetBookings([FromUri] BookingSearchParameters params)
    {
        ... do stuff ...
    }
    

    For the URL to call the method you would basically do what you were doing before but the parameter binding will populate the appropriate values inside your parameter object.

    You can also use the same object if you want to POST values to a similar function.

    We use this method for a search function which normally acccepts a POST from the actual API caller, but I can throw test values at it very easily through a browser to test.