September 6, 2012 1 Comment
Over the past few years I have been building more and more RESTful services in .NET. The need for services that can be used from a variety of platforms and devices has been increasing. Often times when we build a service layer to expose data over HTTP, we may be building it for one platform (web) but know we know that another platform (mobile) could be just around the corner. Simple REST services returning XML or JSON data structures provide the flexibility we need.
I have been very excited to follow the progress of ASP.NET Web API in MVC4. Web API makes creating RESTful services very easy in .NET, with some of the same ASP.NET MVC principals that .NET developers have already become accustomed to. There are some great overview and tutorials on creating ASP.NET Web APIs. I encourage anyone to read through the tutorial Your First Web API for an initial overview.
Another important area to address when it comes to writing RESTful services is the topic of how to provide the ability for consumers to query data. How consumers want to retrieve and interact with the data is not always known, and trying to support a variety of parameters and operations to expose the data in different ways could be challenging. Enter the Open Data Protocol. OData is a new web standard for defining a consistent query and update language using existing web technologies such as HTTP, ATOM and JSON. For example, OData defines different URI conventions for supporting query operations to support the filtering, sorting, pagination, and ordering of data.
Microsoft has been planning on providing support for OData in ASP.NET Web API. In the past few weeks, Microsoft released an OData Package for Web API via NuGet enabling the ability for OData endpoints that support the OData query syntax. Here is a blog post that describes the contents of that package in more detail.
Let’s take a closer look at how to take advantage of this new OData library. In this example below (being a consultant), I build a simple API for returning Projects from a data repository.
Web API provides an easy development model for creating an APIController, with routing support for GET, POST, PUT, and DELETE automatically set up for you by the default route for Web API. When you create a default APIController, the GET method returns an IEnumerable<T> where T is the model for your controller. For example, if you wanted a service to return data of type Project, you could create a ProjectsAPIController and your GET method would return IEnumerable<Project>. The Web API framework handles the serialization of your object to JSON or XML for you. In my example running locally, I can use Fiddler to make requests against my REST API and inspect the results.
After adding a reference to the Microsoft ASP.NET Web API OData package via NuGet, there are only a couple small tweaks I need to make to my existing ProjectsAPIController to have the GET method support OData query syntax.
- Update the return type of your query (and underlying repository) to be IQueryable<T>.
- Add the [Queryable] attribute to your method.
What is happening here is that by returning an IQueryable<T> return type, we are deferring the execution of that query. The OData package then, through the Queryable attribute, is able to interpret the different query operations present on the request and via an ActionFilter apply them to our Query before the query is actually executed. As long as you are able to defer the actual execution of the query against your data repository in this fashion, this practice should work great.
Let’s try out a couple of queries in Fiddler against my API to show OData in action.
Query: /api/projects?$filter=Market eq ‘Seattle’
Query: /api/projects?$orderby=StartDate desc&$top=5
The list of OData URI conventions for query syntax is extensive, and can be very powerful. For example, the TOP and SKIP parameters can be used to provide consumers with a pagination solution to large data sets.
One key concept to understand with OData with Web API is understanding the capabilities and limitations around when the query parameters need to be applied against your data repository. For instance, what if the data repository is not able to support returning an IQueryable<T> result? You may be working with a repository that requires parameters for a query up front. In that case, there is an easy way to access the OData request, extract the different parameters supplied, and apply them in your query up front.
The mapping of operations and parameter to your repository’s interface may not be ideal, but at least you are able to take advantage of OData and provide a standards-based experience to your consumers.
Support for building RESTful APIs in .NET just keeps getting better and better. With ASP.NET Web API and the upcoming support for OData in Web API, you can build dynamic APIs for multiple platforms quickly and easily.