Web API 2 REST Service Advanced Data Filtering

11,195

From the comments above:

You should look into the oData implementation for Web API, there are a couple of MS NuGet packages you have to install. After that its mostly configuring what you want to expose, any restrictions you want to limit the callers to (like max page size), and the rest is done by the client by manipulating the URL to filter, page, sort, etc.

Here an example:

Url sample

This retrieves the top 24 schools in the list sorted by name where the number of students is between 10 and 100 inclusive

/odata/Schools/?$count=true&$top=24&$skip=0&$filter=(numberOfStudents ge 10 and numberOfStudents le 100)&$orderby=name desc

SchoolController.cs

using System.Web.Http;
using System.Web.OData;
using System.Web.OData.Routing;

[ODataRoutePrefix("Schools")]
public sealed class SchoolODataController : ODataController
{
    private DbContext _context; // your DbContext implementation, assume some DbSet<School> with the property name Schools

    public SchoolODataController(DbContext context)
    {
        _context = context;
    }

    [EnableQuery(MaxNodeCount = 200, MaxTop = 100, PageSize = 64 )]
    [ODataRoute]
    [HttpGet]
    public IHttpActionResult Get()
    {
        return Ok(_context.Schools);
    }
}

WebApiConfig.cs

using System.Web.Http;
using System.Web.OData.Builder;
using System.Web.OData.Extensions;

public static class WebApiConfig {
    public static void Register(HttpConfiguration config) {
        // other code
        config.MapODataServiceRoute("odata", "odata", GetModel());
    }

    public static IEdmModel GetModel()
    {
        var builder = new ODataConventionModelBuilder();
        builder.EnableLowerCamelCase();
        var setOrders = builder.EntitySet<SchoolModel>("Schools").EntityType.HasKey(x => new { x.SchoolId });
        return builder.GetEdmModel();
    }
}

NuGet packages

Install-Package Microsoft.AspNet.OData
Install-Package Microsoft.OData.Core
Install-Package Microsoft.OData.Edm
Share:
11,195

Related videos on Youtube

AussieJoe
Author by

AussieJoe

BY DAY: Conformist to society. BY NIGHT: Non-conformist to society. FOR FUN: Eucalyptus leaves, duh.

Updated on June 04, 2022

Comments

  • AussieJoe
    AussieJoe almost 2 years

    My team has currently implemented a REST API (JSON) using the Web API 2 platform for .NET. We have some working URLs, such as:

    /api/schools 
    /api/schools/5000 
    /api/occupations 
    /api/occupations/22
    

    And here is some of our data controller code:

    public class OccupationsController : ApiController
    {
        // /api/Occupations/1991
        public IHttpActionResult GetOccupation(int id)
        {
            var occupation = GetAllOccupations().FirstOrDefault((p) => p.OccupationID == id);
            if (occupation == null)
            {
                return NotFound();
            }
            return Ok(occupation);
        }
        // /api/occupations
        public IEnumerable<Occupation> GetAllOccupations()
        {
            var ctx = new TCOSDBEntities();
            return ctx.Occupations.OrderBy(occupation => occupation.Title);          
        }
    
    }
    

    We are now introducing data filtering (based on user checkbox selection) and I am curious how to approach this in our existing API, or if I should abandon REST for filtering down and try a different approach all together?

    Here is our checkbox filtering mechanism: Checkbox UI

    How can I introduce search parameters in my REST services and DataController methods? Like, how do I get a range filter on a field (like Cost?)? Can I have multiple fields filtering, like Cost, Tuition, etc?

    • Igor
      Igor about 8 years
      You should look into the oData implementation for Web API, there are a couple of MS NuGet packages you have to install. After that its mostly configuring what you want to expose, any restrictions you want to limit the callers to (like max page size), and the rest is done by the client by manipulating the URL to filter, page, sort, etc. See this link and this to get started.
    • Igor
      Igor about 8 years
      By the way, I'm not advocating you use oData as a blanket approach to everything, just those particular models where you want to expose flexible retrieval by the/a client.
    • AussieJoe
      AussieJoe about 8 years
      Is it possible with Entity Framework? I noticed the OData example is without EF? I like it though!
    • Igor
      Igor about 8 years
      Absolutely. I have been using it for the past 6 months in our projects. Our client's are web browsers so we built a library to create the oData query string (level of abstraction to hide the odata query details). I really could not be happier, it saved us a lot of c# code each time we wanted to expose a model where we wanted flexible searching. Also, with EF, you pass an IQueryable and the database call is executed by the oData framework so its also light weight. The only negative I can think of is its a leaky abstraction in that you are exposing implementation details to the caller.
    • Igor
      Igor about 8 years
      Anyway, for scenarios like yours above I really do recommend it.
    • AussieJoe
      AussieJoe about 8 years
      @Igor Any chance you can provide a sample so I can give you the answer vote? I have implemented it and its really nice :)
    • Igor
      Igor about 8 years
      Here you go, hope this is of some help for you.
  • AussieJoe
    AussieJoe about 8 years
    very nice! works like a breeze. I like this solution alot! Cheers!
  • Igor
    Igor about 8 years
    @AussieJoe - glad to hear it!
  • AussieJoe
    AussieJoe about 8 years
    Is it possible to use traditional Web API and OData as well in the configuration? I noticed when I converted my School controller to OData, my other ApiController's no longer work. Can they work together or must all controllers be OData in the API?
  • Igor
    Igor about 8 years
    @AussieJoe - Yes, they can be side-by-side in the same project with out any issues. Make sure you add the new route info (like in my example) next to the existing api route info. I have my web api routes prefixed with the default "api/" and the odata routes prefixed with "odata" (like in the example).
  • SUN
    SUN over 6 years
    @Igor can you post complete implementation of this including dbContext? I am beginner to web api so need to understand .