The journey to GraphQL from REST

Abe Petrillo
AlphaSights Engineering
4 min readMay 16, 2016

Here at AlphaSights we made the bold decision of migrating our SOA to GraphQL from REST. You can find out more on implementation and code by reading Steve Aragon’s great post on using GraphQL in Ruby, and how we are using our open source addon for the client side. This post is more about the benefits we experienced, the troubles we encountered, and what’s next.

The Good

The best part of the process was getting to a point where we could address our technical debt. We looked at the Domain Language we wanted to deliver to our consumers, and how to best deliver that data from the server side. This helped us isolate the problems we had with REST, such as:

  • Multiple endpoints delivering the same data in different ways
  • Optimizing the performance of each endpoint
  • Maintaining multiple areas of legacy

Multiple endpoints created havoc when attempting to debug a problem or refactoring a feature with one of our consumers. Having to figure out the potential code paths of a given piece of code and hoping that all endpoints are using the same abstractions from numerous endpoints can be a daunting task. In many cases we had to rely on integration tests which, when failing, can be quite time consuming.

Optimizing performance was an interesting one. By knowing how we had to resolve the queries based on type, we are able to use dynamic optimizations. We can use `pluck` for the requested attributes, and `includes` for requested associations. Using a mapping function to pick the right include based on requested node names proved quite straightforward.

GraphQL gave us one way in, and one way out. All data was resolved through one object, `Graph::QueryType`. The presence of only one object provided a much easier learning curve for new developers looking at the code base, and the higher level concepts each have their own resolver making it easy to narrow down what each term meant right down to the database level. The mapping of types from a query into ruby objects is very intuitive, for example:

Someone exploring a fix for a problem with this specific query can navigate to the `QueryType` definition and see how that type is resolved:

As you can see, each argument, or “param” if you are familiar with Rails, is quickly explained, but you can also assign a type to the parameter which provides a bit more context around what the server expects. This lets you avoid digging through finding the `strong_params` method, then digging through the code to see where the string value is turned into something useful. Although this is a contrived example, even if there are layers in between QueryType and the database, you still have that one entry point, and have to provide a consistent output.

By making the server to consumer contract flexible, we get the benefit of much more agile teams, and less debate on how and if the consumer receives that data. We have also found that maintaining the services is much easier. There are no “v2” routes to be added, and the type system allows the consumer to easily discover updates. We have also taken advantage of “GraphApi::Schema.middleware” to monitor which attributes are being used, and help identify legacy types/fields that we can remove, which we are going to open source in the future.

The Bad

We have struggled to come up with a consistent solution for handling errors. While you can make the error messages consistent based on the problem, applying a regex to a string to react to an error is not ideal. Given the already existing support from HTTP protocol like 404, we have lost some “magic” from Rails which would have done this for us. For now we are either outputting the error string generated by the gem to the user, or in the case of an app to app scenario we have an agreed format sent via the error message similar to:

We’ve also had problems with passing null as a value of an attribute, where arguments containing nil were not behaving as expected when compared with REST. This does seem to be getting addressed in the proposed RFC change.

TLDR;

In moving on from REST, we have also had to leave behind some of our tools. This means that we had to create some new ones, or rely on a younger, sometimes less stable toolset. While client side frameworks such as Relay support the developer quite well, our main client side framework is Ember. Getting Ember to co-exist with GraphQL, by using our GraphQL Addon has proven to be a challenge. That being said, the benefits of a more maintainable codebase and a reduced barrier to entry for new developers on the team has been great. Combined with the flexibility that is needed in a fast moving world with ever changing requirements. The experience, while challenging, has been a success.

--

--

Abe Petrillo
AlphaSights Engineering

Software Engineer @AlphaSights, Ruby developer and JS addict