OData (the Open Data Protocol) is a standardized protocol for creating and consuming data APIs. OData builds on core protocols like HTTP and commonly accepted methodologies like REST. Using OData allows you to expose full featured data operations (Query + Update) to build a generic API quickly and easily.
A few months ago I was trying to build a web service for my new start-up and I happened to read some articles about OData, for example, this, this and this. Of course, I also poked around the offical site and they claim that OData is the best way to build REST (they use font-size 63px, how can you not believe them?).
Initially it did sound like a very good idea to rapidly build a complete API. For example, a URL: http://services.odata.org/Northwind/Northwind.svc/Products?$top=10&$skip=0&$orderby=ProductName&$inlinecount=allpages performs paging and sorting directly in the URL query string. With all the options such as $filter, $select and $expand, technically I only need one method to return the root entity in IQuerable.
I was happy at the beginning. However, after a month of using it, I finally decided to ditch it and went back to WEB API.
Sorry, OData, it's not your fault. It's me.
I was confused by the version of OData. Microsoft has both V3 and V4 on nuget. I can understand why they are doing it. Unfortunately, when I first set up my project. I probably pulled the V3 library. But I was reading documentation on V4 (sigh). There are a few things are different. One example is Function doesn't exist in V3. Long story short, I wasted a lot of them on figuring out why my code didn't work; after I changed to a way to make it work, it stopped working after when I upgraded to V4. Anyway, it was a mess and I got frustrated.
If the first reason didn't convince you...well, technically it only showed that I was stupid, this reason might be better.
You can expose CSDL from OData by accessing http://yourserver/odata/$metadata. It then shows everything to the user, including the data schema and all available functions/actions. For example, the image shows what you would see. It could be a good thing if it is an internal API, but personally I don't like this powerful discoverability for a public API.
Basically all tutorials I have found online are returning data entities directly from controller. It is fine to do so in an example, but that is not real life. I don't really want to always return data entities directly. In some cases, I have tried to return my DTO, and then some options ($filter, $skip, etc.) failed to work. After digging for a while, I found out that I would have to do a lot of complex configuration and extension to return DTO while have the OData full support. I was obviously disappointed, because I was expecting to do less but found out having to do more.
While many methods in my controller are returning IQuerable, it makes them very difficult to test. But who am I kidding, I didn't write any test code. :)
I don't know and I don't think I can answer that question. To me, OData builds a generic API, which is so powerful that I could just need one methods as long as they are all linked. This is firstly against the single responsibility principle because I found out my client code (of different pages) ended up using the same operation with a series of long different query strings.
On the other hand, I do prefer to have operations with specific meaning and usage. It does not only help maintain it in the future but also help reduce the complexity of testing.
I realized it later that if I want to take the full benefits, such as have the query string option support, my data entities must have all the navigation properties. In another word, they need to be linked. Initially, I didn't want to use DBMS, even though personally I am not opposed to. I tried not to have any relationship among my entitie (in a loose form); however everything failed.
After a month of struggling, I finally ditched OData and switched back to WEB API. From the standard of the OData protocol, it certainly looks very appealing and powerful. Unfortunately, implementation-wise, it is still currently suffering.
In the end, I would like to recommend some other posts talking about this topic in depth: