Introduction
It is more than a common scenario that our apps(be it mobile apps or web apps) are backed by a service. These services are often RESTful these days as the benefits and flexibility of REST in undeniable. But its more than often that I see these services that are being written for consumption from the apps tend to have the endpoints exposed as per client app requirements. We recently inherited some code for a project that is an ASP.NET Web API that is meant to be consumed by an angular app(phonegap based hybrid mobile app). To my surprise this Web API is exposing the endpoint that is tailored for angular app needs. Things like, page size, page number, search sort etc are being passed to the API's action method to get the filtered data on the app.
Background
I could be wrong but to me it felt like in some way approach like this is polluting the Web API based since the API endpoints are being dictated by client app requirements. What if we have another app that has some different kind of requirements for data. Will we be exposing more endpoints to cater to that. The most painful point is the implementation that exist for each endpoint. We have to have action methods on the API end to cater to these requirement. Ultimately the API get bloated catering to all these needs and becomes a maintenance nightmare.
There is nothing wrong in this approach but the point being if it is serving our purpose and we are able to live with the complexity. But for such services why not follow a rather standardized approach. If you are thinking ODATA then you are right on the money.
ODATA is a protocol using which we can share and access the data using AtomPubprotocol. This AtomPubprotocol is mainly used in creating feeds from websites. It is built on of the REST architecture philosophy where the CRUD operations in the remote data resource can be performed using HTTP protocols like GET, PUT, POST and DELETE.
For more information on ODATA: http://www.odata.org/
ODATA and ASP.NET Web API
Now from the ASP.NET Web API perspective its rather very easy to support ODATA. The best part about having a Web API is that it is already built for creating restful services. And it is rather very easy to create the ODATA compliant Web API. If I have to put it in simple words - Creating an ODATA compliant Web API is just a matter of importing a nuget package. In fact visual studio comes with a scaffolding template that can be used to generate the ODATA compliant API controllers. All the magic of converting the APIControllors into ODATA compliant controllers is in the following nuget package: Microsoft.AspNet.Odata
.
For a step by step tutorial on how to create ODATA compliant Web API: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/create-an-odata-v4-endpoint
The only thing to note here in case we use the visual studio scaffolding for ODATA API controller is that it will put the ObjectContext
and data access code in the controller itself. Which is perhaps not a good idea from patterns perspective. So in case we want we want our controllers to use the Repository pattern, we just need to make sure that our repositories return IQueryable
and not IEnumerable
and the ODATA package will take care of the rest.
UPDATE: Someone asked a very interesting question about how the connection management will work with this. To clarify on this point, using ODATA does not mean that we are creating a live connection between client server. Its the parameters that are being passes in ODATA format and the controllers are evaluating the paramters in the traditional way they would have managed in a plain APIController. To understand this a but better lets look at a method created in the Controller.
public class MoviesController : ODataController
{
private MoviesDbEntities db = new MoviesDbEntities();
[EnableQuery]
public IQueryable<Movie> GetMovies()
{
return db.Movies;
}
}
In the above code, connection management is no different here than the traditional action methods. since the Context class object will get disposed as soon as the controller gets disposed.
SO how does ODATA queries work magically? What happens here is that the attribute EnableQuery
that is put on top of our query methods look at the ODATA specific parameters in the URL/querystring. It will then take the return values from our action method i.e. the IQueryable
and apply LINQ on that depending on what IDATA parameters were passed by user(before returning it to the caller). After this LINQ is applied and the final data is ready to be returned, the dispose method of the respective context class and the controller will get called taking care of the connection disposal.
Note: The overall Philosophy here is to let the service expose the data in a standard format and apps consume the data using this format. No need to expose endpoints based in consuming apps requirements. I just provide references to be able to create ODATA compliant ASP.NET Web API but the same philosophy can be utilized by any technology stack.