Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Choosing OData or REST ? Detailed Analysis

Tags:

odata

Below is the Analysis from various web-sites about Odata.

Background about Odata

1. open standard and web protocol. protocol to expose data over the internet
2. developed by Microsoft, managed by Oasis Org
3. open data protocol - allow creation and consumption of query-able and inter-operable RESTFUL APIs
4. best way to REST
5. used by mobile and web app widely
6. all info about odata - odata.org
7. odata reference services - https://www.odata.org/odata-services/
8. querying and updating data
9. built on http and sends data using Json/Atom
10. support various advanced query language. example
    a. filtering and ordering data - http://../api/Orders?$filter=Total gt 1000$orderby=shippedat
       desc
    b. navigating through relationship - http://../api/Orders(451)/Lines(4)/Product/Name
    c. client side paging - http://../api/Orders?$top=10&$skip=10 and ~/Products/$skip=70&$top=10
11. Asynchronous queries
12. Odata protocol allows the publisher to tag and label the data with domain specific vocabularies.
13. Access data from any platform or device
14. OData shares some similarities with JDBC and with ODBC; like ODBC, OData is not limited to 
   relational databases.

What problem Odata solves?

Data Api's frequently create more problem than solutions. many web-sites exposes data via apis
(ex: facebook, twitter)

Ex: facebook: what fields will i get when you read a post? time, user name
    twitter api: list of user's following me and unfollow someone (ex: post 
    https://api.twitter.com/1.1/friendships/destroy.json with id)

Usual problem: how to developers know ? they need to go through the documents. if API is changed, 
               then the request will be changed. uniformity increases the time needed to learn the 
               API. 

Reduces the amount of time to design an API.  

Rest Issues?

a. URL structure i.e how do you want your URL looks
b. search
c. how do you use the method consistenly 
d. how do you create a new resource

Difference between OData vs REST

OData prescribes conventions that REST doesn't

   a. Representation formats
   b. Precise verb meaning
   c. URL conventions for filtering, paging etc.,

Other differences

1. The problem is that ODBC allows clients to initiate transactions across multiple requests. REST 
   does not allow this as it would violate the stateless constraint. 
2. OData is a specific protocol where as REST is architecture style and design pattern
3. All OData is REST, but NOT all REST is OData.

Negatives or Drawbacks of Odata

1. anti-pattern - provides both a weak contract and leaky abstraction. development and API practices 
   by providing a black-box framework to enforce a generic repository pattern.
2. An API should be designed with a specific intent in mind rather than providing a generic set of 
   methods that are automatically generated. OData tends to give rise to very noisy method outputs 
   with a metadata approach that feels more like a WSDL than REST. This doesn’t exactly foster 
   simplicity and usability.
3. allows remote clients to execute database queries remotely over HTTP which can only give rise to 
   complex and fragile integrations that break under the weight of edge case problems.
4. OData stems from an era (the 2000’s) where everything had to be XML (and SOAP ugh!). That era has 
   luckily passed and the open web has moved on to other simpler & more efficient formats & protocols 
   like JSON or protobuf etc.

Reference Links

1. http://pragmatiqa.com/xodata/ for non-developer to play with Odata
2. https://www.odata.org/odata-services/ - Odata Services
3. https://en.wikipedia.org/wiki/Open_Data_Protocol

What is needed?

  1. Looking for a detailed feedback/comments to know whether to go with Odata v4 or choose REST. Some says Odata is outdated and doesn't fit for new generation or next generation app. Not sure.
  2. Sample working Odata app and database to play with or work with to understand Odata better.
  3. Best way to quickly learn or get upto speed on Odata.
like image 628
Java Architect Avatar asked Jan 29 '20 12:01

Java Architect


Video Answer


1 Answers

Lets be honest, the reason that there was no response to this earlier is that this topic and the way the question was asked is too broad to be properly on-topic for SO. I'll draft this here and find somewhere else to publish it later ;).

OData IS the best way to REST
An open protocol to allow the creation and consumption of queryable and interoperable RESTful APIs in a simple and standard way.

OData Protocol Overview
The OData Protocol is different from other REST-based web service approaches in that it provides a uniform way to describe both the data and the data model. This improves semantic interoperability between systems and allows an ecosystem to emerge

Many of your arguments both for and against are outdated or unfounded, so I don't want to address each of them individually, but the reason that OData was created in the first place was to address the sprawl of unique interpretations of what a REST API means by creating a standard for these aspects of APIs:

  • Describing the resources and capabilities of an API (CSDL)
  • URL Routing conventions
  • Response Formats and Structures
  • Aggregated Queries across Resources

While anyone can say their API is REST based on the fact that it uses HTTP requests, is uniform within itself and might be stateless, a Rest API that is OData Compliant is a specific implementation that follows the guidelines described in the OData protocol and specifically constrains the definitions of what a resource is and how different resources can be related to each other.

Fundamental to the OData protocol is to the idea that the standards should keep API development simple for both developers and consumers. The common standard has facilitated the evolution of libraries and frameworks that significantly reduce the common boilerplate logic that each API requires to conform to these standards.

Another key factor that OData addresses is that APIs often provide more data and metadata than many clients require, which leads to unnecessary bandwidth consumption. Some APIs address this by creating multiple endpoints that serve different structures or views for the same resource, OData provides a Query language that allows clients to specify how much detail they require from a request, but importantly there is limited scope to modify the resource, you can only reduce the schema that is returned by omission of the properties that you do no want transmitted. In this way the structure of responses will remain consistent, which is especially important for some client-side implementations.

  • in OData 4.01 it is now possible for us to make additive changes to the schema as well via the $compute operator.

PATCH

Reducing the bytes over the wire also comes into play with the partial update via HTTP PATCH. From a pure REST point of view, PUT should be used to update an existing resource, it is guaranteed to be idempotent. Thta means a real REST architecture should respect any and ALL content provided via PUT request and subsequent calls to GET the same resource should return the same content. This is problematic in Application Design, especially in a scenario where 2 users update a different fields in the same resource at a similar time.

  1. User John executes a GET on the resource X (which represents a Prospect)
  • John is from Sales, he is updating the status of a lead that includes some lengthy notes on a new proposal before calling , so it will take a few minutes before they submit the PUT
  1. User Jane executes a GET on the resource X
  • Jane is from Admin and is processing a request to change the contact number for the Prospect

Unless each client application is tracking changes and executes a new GET immediately before submitting a PUT to ensure that they have data that is up to date, or you try to do something similar on the service side, then one of the following scenarios will occur:

  1. John submits first, then Jane submits. Jane's submission didn't have any of the data that John has entered, Jane's PUT will overwrite Johns. We will lose all of Johns changes, including new contract arrangements or offers

  2. Jane submits first, then John. John's submission overwrites Janes, so the new contact number is lost and the record retains the previous value.

In both cases, there are not likely to be any errors raised, at the point in time of the submission in both cases, the API will override the stored content without question, that is what REST tells us to do.

There are workaround for this, like comparing the ETag first before processing a PUT request, but then the client would need to know how to handle potential failures which will result in either a poor user experience or a lot of code to maintain.

OData actually introduces a new issue with PUT, if it is possible to query only a single property from a resource via $select, then if you were to pass that same value back in a PUT then now the entire resource is nulled out except for the single property that was PUT back into that resource.

PATCH allows us to send a differential structure (AKA Delta) that only contains the properties that you wish to change. In this way the previous John vs Jane scenario is avoided as long as both John and Jane are not trying to edit the same fields. This is a more advanced optimistic concurrency scenario, but due to $select it is really important to avoid the client accidentally nulling out properties that the client may not have even been aware they existed.

In an OData implementation it is a good idea to disable PUT altogether.

The last comment "properties that the client may not have even been aware they existed" is more important than it sounds at first. Over time, it is likely that the Schema of your API is likely to change, and your clients are not likely to change as fast or at all in some cases. This can cause significant issues when PUT is used and it can be hard to identify when it becomes a problem. If the client code uses serialization techniques that do not retain the original JSON schema, for instance if you deserialize into a strongly typed interface, then it is common for additional fields that do not match the interface contract to be excluded. Then on a subsequent PUT the original state of the missing fields, even though the client code didn't make any changes to it, would effectively be deleted.

PATCH when implemented correctly has an enormous impact on the integrity of data as well as performance, most CRUD data operations will only be modifying specific fields, not every property on the resource. PATCH reduces bandwidth consumption and reduces to data merge conflicts that might still occur to just those specific fields that are entered by the different operators at the same time.

Why Choose OData

OData is commonly chosen as part of a Rapid Application Development (RAD) SDLC process, I only have anecdotal evidence to support that, but the features of OData correlate very closely with RAD priorities. The idea that we can quickly expose the bulk business application framework and start prototyping the client implementation is very tempting on its own, but hyper important in a RAD process, the front end devs need the API to start coding against, often before the API guys have fully defined all of the behaviours and operations available.

OData fits the throw away prototype culture of RAD development because the client developers can use the rich query capabilities to access data in ways the API designers hadn't yet considered. Through the feedback from the each cycle of the development process, Functions, Actions and new Aggregates will be added to the Business Model to create efficiencies and enhance the next iteration of client side development.

Fundamentally the underlying Business Resources are not likely to change throughout this process, a change to the Business Model is after all a change to the Business. Complex queries from the client, however inefficient will do the job, hoever any complex logic from the client should be transitioned through to the API layer to reduce the logic on the client

What are the Cons to OData, why wouldn't you use it?

Most of the critisms against OData are against specific implementations and the lazy or relaxed patterns implemented in many APIs. For instance the latest version of .Net (6) comes with support for exposing an entire database via conventions through a single coded controller in less than 40 lines of code. Implementations like this that just expose everything are considered an anti-pattern because all they are doing is exposing a query mechanism through an abstraction layer, presumably the assumption is that there is no Business Logic implementation.

40 lines of code to get a server operating might sound appealing to some teams but this would be a very rudimentary API and it is generally expected that you would take more care to expose a rich set of Business Entities, Views (Functions) and Operations (Actions) outside of the standard CRUD capabilities.

In fact a well designed OData API will explicitly filter the available operations, routes and query options based on the security and business context needs, just as you would with and other REST based API.

OData is NOT designed to be a simple database query engine. It can be used to do this, and is really good at it, if that is your intention, but that is NOT the point of it.

OData allows your Business Domain Model to be queried, NOT specifically the database. If you choose to design your database schema following DDD principals, then it might be entirely appropriate to expose the database schema almost in its entirety through the OData protocol. But that is an implementation decision that sits purely with the author of that API, there is no requirement to expose a database at all.

All OData implementations require you to define the model via the CSDL, it is part of what makes OData stand out from other protocols, you must describe the model. This is also part of the reason why it is harder to implement an OData API, you are forced to describe things adequately and in a way that conforms to the protocol.

I said I wouldn't but lets address each of the drawbacks that were listed, noting that the primary source was an an article on Ben Morris.com about Netflix failing to deliver a robust API in 2013 for their business use case. - sorry that's a bit critical...

  1. anti-pattern - provides both a weak contract and leaky abstraction. development and API practices by providing a black-box framework to enforce a generic repository pattern.

So all APIs could be considered "black box" and really should be, that is the point of the API to abstract away the internal implementation so consumers only see the business implementation. OData at least defines the input and output structure at a protocol level, a protocol cannot really offer much else other than the general expectation on how CRUD operations will be accepted.

As with all applications, the success of the product is usually less about the protocols used, and more about the business implementation and accessibility to the consumers. I am not familiar with the specific use cases that caused contention at Netflix, but it sounds like the structure of the data was not conducive to consumers and user adoption, it sounds very much like a DDD was NOT implemented very well. In this case OData is only to blame because of the ease of which they were able to publish the data schema and that they chose to use a very relaxed set of conventions to base their business model on.

  1. An API should be designed with a specific intent in mind rather than providing a generic set of methods that are automatically generated. OData tends to give rise to very noisy method outputs with a metadata approach that feels more like a WSDL than REST. This doesn’t exactly foster simplicity and usability

Um... OData forces you to explicitly define the intent, that is precisely what makes OData different. There is a single metadata document that describes the intent and structure of the entire schema if you wish to read it, if developers wish to provide that level of documentation. WSDL (SOAP) and XSD are the only other standard protocols that I am aware of that are highly specific to inputs and outputs, OData is a lot less prescriptive and focuses on data types, enums and nullability.

The fundamental difference with OData is the heavy focus on resource items and collections. It takes some effort to design your business model around this resource concept, especially if your database schema is no inline with this.

It doesn't matter what the protocol is, an API should be designed with specific intent in mind, OData is no different. Just because OData allows the client to control the content through a rich query language is no less indicative of intent, but it des allow the client callers some flexibility capability

The same article is critical that OData is like WSDL as if that is a negative thing, but then crusifies OData from not being prescriptive enough, so I think this point is moot.

Most of us agree that from a programming point of view WSDL is too specific and therefore prohibitive, and that REST on it's own is too ambiguous. OData attempts to create a middle ground, the descriptive language is specifically designed to convey all the information that youneed to generate the necessary request and response structures in the client implemenation, which matches the same information that would be intrinsically available if the API was a simple code reference that was included in your client-side project.

  1. allows remote clients to execute database queries remotely over HTTP which can only give rise to complex and fragile integrations that break under the weight of edge case problems.

As explained above, many OData APIs might expose direct database queries, but that is an implementation detail, there is no requirement to do this, the queries are against the Business Domain Model, if the author maps that directly to their database then that is precisely what they wanted to do and would likely do the same thing if forced to use another implementation.

  1. OData stems from an era (the 2000’s) where everything had to be XML (and SOAP ugh!). That era has luckily passed and the open web has moved on to other simpler & more efficient formats & protocols like JSON or protobuf etc.

I have no words, this again is the negative reference to SOAP, but OData is the very embodyment of moving on from SOAP and XML. Yes the $metadata document is expressed in XML, but that is very deliberate and no apologies are made for this, JSON does not have the necessary semantics to fully express all that needs to be documented in the CSDL without an accompanying schema document.

Overall the main criticisms of OData revolve around the perception of too much flexibility for the client to do what they want, but the reality is that in many projects we don't always know what the client wants in advance, so this flexibility becomes the main deciding reason to use OData, it is not always a negative concept.

Many devs leave OData APIs wide open, but the same due diligence should be taken in reviewing the cpabilities of endpoints in all APIs before releasing them to the public domain. The main difference is what is normally off or prevented in other APIs may be enabled in OData.

What else is there:

In researching for this post I found a lot of negative content about OData, mostly in the GraphQL vs OData, this article I found to be quite balanced, REST API Industry Debate: OData vs GraphQL vs ORDS. (I had never even heard of ORDS) The closing argument sums things up very well, The concept of OData is really good, the implementation even using all the available tools still takes a lot of work to make your implementation fully OData compliant.

You mention ODBC... Lets call that about as close to directly accessing the database as you can get. The problem with ODBC / OLE DB / ADO is that you are exposing the raw database implementation and that there is little room for encapsulation of Business Domain logic and structures, you would be required to manage all of that into the database layer directly.

  • Thats an oversimplification, but in general ODBC is reserved for high trust environments, so generally internal facing interface, or when the caller manages most of the business logic.

ODBC / OLE DB / ADO are Data Access protocols that your API uses to talk to the databases, the API is essentially an abstraction around these concepts that encapsulates your Business Domain Logic.

If we talk about just different protocols, then GraphQL is really the only other protocol that competes with OData at a protocol level. To choose to go with a simple REST or JSON API is really like saying you will make your own standards in terms of routing, responses and behaviours. Which you are very welcome to do, there are many different libraries that will provide there own implementation standards but to do a proper Pro/Con analysis would require comparison against specific implementations, it isn't fair to say that in general they are any better or worse that OData/GraphQL, they would simply be different and it is up to you what sort of interface you want to expose to your consumers.

The reason to go with a standard implementation is to offload the knowledge on how to consume your API, with OData it is customary in documentation to firstly refer consumers to the version of the protocol that your API conforms to, and the supported vocabularies (because we don't bother implementing 100% of the specification every time). This covers the technical requirements, then you only need to describe specific features of your business domain that are not part of the OData protocol itself.

From a practical sense, implementing OData or GraphQL on your own from scratch can be a lot of work, your chosen language, development environment, deployment environment and skill level may dictate what frameworks would be practical for you to use, the structure of your database or internal services that you are exposing through the API will also factor into the level of effort that might be required for different protocol implementations.

A very simple OData vs GraphQL:

  • GraphQL is great for aggregating multiple services or repository based APIs or microservices where different resources are sourced from different or multiple internal endpoints. If your resources are all centrally located, especially if they are in the same DB then an OData API will be far simpler to implement and manage.
    • GraphQL is IMO the best solution for creating an abstraction layer exposing multiple existing services or data sources through a common API
  • OData is great when there is a single or highly coupled data source where there are very clear relationships between the resources.
    • OData is IMO the best solution for exposing a business schema for CRUD interoperability with a client application or for integrations.

Other than that they generally attempt to solve similar problems in different ways.

like image 107
Chris Schaller Avatar answered Sep 24 '22 06:09

Chris Schaller