For a couple years, I’ve observed scores of developers making ill-informed claims about GraphQL. People have claimed that GraphQL allows the client to demand sorting, paging, and filtering from the server. People have claimed that GraphQL can result in execution of arbitrary queries or joins. People have claimed that GraphQL exposes too much power with not enough server-side control. As I hope to convey through this post, these claims are false.
Not long ago, I saw a tweet from someone making accusations about GraphQL. This tweet was from someone I respect and admire for their frequent display of depth and due diligence, which is why their statement surprised me. One of the replies on the thread was, “Graphql is a fancy name for odata.” I took a deep breath and decided not to engage.
For a couple years, we’ve been using GraphQL with great success at SAP Concur. For a couple years, I’ve reflected on my past experience with OData and my happiness with GraphQL. For a couple years, I’ve sat idly by, trying not to jump in and say, “well, actually…”
Recently, I realized I had gathered most of my thoughts on GraphQL and I felt ready to present them. My irritation distilled down to a single declaration. Without knowing if anyone would take notice, but ready to have the conversation should anyone engage, I posted one simple tweet.
Experience with OData
I spent several years at Microsoft. I contributed to a few projects you might be familiar with:
WCF RIA Services
I had my first experience with OData while working on WCF RIA Services. I started as an SDE II on that project but eventually became the dev manager. WCF RIA Services brought Silverlight and ASP.NET together, allowing you to build Line-of-Business applications with ASP.NET domain/business layers and Silverlight UIs. This combination made it pretty easy to grow forms-over-data apps into business-logic heavy applications, keeping the business logic out of the UI through a clear separation of concerns.
WCF RIA Services allowed you to either expose your domain model directly to the client or create and expose a view model. By authoring CRUDE (create, read, update, delete, execute) operations and annotating them, you could easily create an API for your client to consume. But we needed a protocol for serializing requests and responses for those CRUDE operations and the data to go along with them. We ultimately landed on using some WCF primitives.
Before we solidifed our decision that we’d use WCF, our project was just called “RIA Services”, where RIA stood for “Rich Internet Application.” Using WCF resulted in prepending our project name with WCF and, believe it or not, getting reorged into the WCF group. This was all good though–to use WCF was far better than our proprietary protocol developed in our early preview releases.
WCF RIA Services was pretty well engineered. We were promoting a separation of concerns for applications built on our framework, and we ourselves kept our concerns separated. This led to both the server and the client being decoupled from the communication protocol. We were able to swap out that layer independently–largely because Wilco Bauwer is amazing. Wilco swapped out our proprietary protocol for WCF in days. And we demonstrated we could support multiple protocols in parallel.
Along came OData. Microsoft was pushing OData pretty hard for a while. Some really sharp folks in the SQL Server group invented it and OData had a lot of muscle behind it. It became clear that we needed to support OData for WCF RIA Services. After some long debates, we ultimately landed on the decision of:
WCF RIA Services would support OData as an optional protocol
But it would not use OData by default
We then created the OData protocol library in the WCF RIA Services SDK and made it easy for an application developer to swap out the default protocol for OData.
I don’t remember the arguments I had against OData during those debates, but I do remember one very specific incident that occurred after we shipped the SDK with OData support–a vulnerability in the OData specification that allowed remote code execution that could result in denial of service. You could kill an OData server with a single, well-crafted GET request. Oops.
During a reorg, when ScottGu took on leadership in Azure, the ASP.NET group merged together with the WCF group. This opened up opportunities for projects like ASP.NET Web API. It also opened up an opportunity for me to expand my scope at Microsoft; I got to work on ASP.NET and NuGet.
I joined the NuGet team right as NuGet 1.5 was shipping. At that time, it was basically a side project, with everyone on the team also working on other products. NuGet was open source and the client was downloaded through CodePlex and installed as a Visual Studio extension.
NuGet, like every package manager, needed a public package repository. NuGet.org was built by our team, which happened to be the same folks working on ASP.NET MVC, ASP.NET Web Pages, Razor, and a few other products. Can you guess what protocol we were told we must use for the NuGet client to connect to the NuGet Gallery?
You guessed it: OData
I’ll save the details for when we get together over beers, but that choice didn’t work out very well and the team has been working to change course for years. Howard Dierkingand I worked together on NuGet and we spent a significant portion of our time figuring out how to unwind OData out of NuGet.
Here are some reference blog posts that shed some light on the effort:
Experience with GraphQL
Our group was embarking upon a monumental effort of re-engineering our UI. Concur’s legacy monolith had been built as a two-tier application with the UI talking directly to data sources (including databases). We needed to separate concerns, break the UI out of the monolith, start adopting modern UI technologies, and concentrate on building a scalable, user-friendly, accessible, maintainable UI layer.
We quickly selected Node and React as core technologies. We also studied the Flux architecture pattern that complemented React’s unidirectional data flow. We started using fluxible and other flux libraries, but when redux hit the scene, it took over.
Concur had already been breaking APIs out into microservices; we were a couple years into that journey when Howard and I joined. So how would we get our UI talking to the dozens of services?
You guessed it: OData
Filling a Gap
We were using fetchr pretty early on and it was pretty cool. Fetchr gave us a protocol and took care of a lot of plumbing, but it was very CRUD-oriented, which we didn’t love. We knew we wanted something to sit between our APIs and our UI that would serve as a façade, but we didn’t know what would fill that gap. Until GraphQL was announced.
As soon as GraphQL was available, Simon and Howard were all over it. They knew we needed to invest in using GraphQL; they saw the power of transforming the shapes coming out of our APIs into what our UI needs. They appreciated the simplicity of GraphQL’s protocol and its explicitness for both the client and the server. Simon and Howard recognized that our group could build the GraphQL layer independently from the groups building the APIs.
When Simon and Howard presented GraphQL to me, I was immediately sold. Within literally 5 minutes, the lightbulbs were going off for me and I was infatuated with GraphQL and ready to use it. We started putting plans in motion so that we could:
Build, deploy, and operate a GraphQL server in Howard’s platform group
Connect the new Node/React/Redux UI applications built in my group to GraphQL
Design GraphQL schemas and resolvers that could be shared across mobile and web
Connect the GraphQL server to the various microservices needed
Even connect GraphQL to some legacy APIs where new APIs didn’t yet exist
Innovate in the GraphQL layer at a pace independent from both the UI and the APIs
We’re more than two years into our experience using GraphQL at Concur. Overall, it’s been very positive. Sure, we’ve had our stumbles; we’re midstream on “version 2” of how we approach GraphQL organizationally. But we need version 2 for a great reason–the usage of it has outgrown the organizational structure we built around it. And as Conway’s law asserts, our implementation mimics the organizational structure, so the implementation will change in version 2 as well.
“organizations which design systems … are constrained to produce designs which are copies of the communication structures of these organizations.” –Melvin Conway, 1967