GraphQL Ruby: Clean Up your Query Type

Steve Aragon
AlphaSights Engineering
4 min readMar 14, 2016

From RESTful to GraphQL

At AlphaSights, the team I work on is writing an ambitious web application that redesigns our core workflow. At first, this application used a RESTful API to communicate between the Ember frontend and the Rails backend. Now, we are moving over to a GraphQL API which has only one endpoint from which to query and modify the database.

To implement this, we are using are own homegrown Ember Data GraphQL Adapter as well as the GraphQL Ruby gem. If you’re unfamiliar with either, watch this video for an intro to GraphQL given by my AlphaSights colleague, Ju Liu, and/or check out this GraphQL Ruby tutorial from the gem’s readme.

Some Query Type of Way

I am going to assume that you already know a little bit about GraphQL and the GraphQL Ruby gem, but here’s some additional info on what goes into your GraphQL Ruby schema (from the gem’s docs):

- Types which expose objects in your application- Fields which expose properties of those objects (and may connect types to other types)- Query root, which is a special type used for executing read queries- Mutation root, which is a special type used for executing mutations

The main file we will look at is our query root, named query_type.rb in our schema, which can become quite complex as you build up the functionality of your GraphQL endpoint.

A simple example of a GraphQL query_type.rb

For this example, we are working on an app that keeps track of players on a team.

Looking at the query_type.rb, we notice that we have a simple field, player, which grabs the player data using its id.

Next thing we notice is the more complex players field which contains an if/else statement within its resolve block.

We’ll want to abstract this out, which should make the code easier to follow and modify. Knowing you need to move the code is easy, but where/how do we move it?

Resolvers?!

We started using what we call resolvers to house our more complex resolve blocks. We isolate our if/else statement in our players resolver, below.

A Resolver class for our players field

Since we know that these lines of code from the query_type.rb

-> (obj, args, ctx) do
...code...
end

…are creating a lambda, which will eventually have call called upon it, we can write a call method and pass the arguments from (obj, args, ctx). Also you’ll notice, we are only using arguments in the call method, so we use underscores for obj and ctx to note their unimportance or lack of use.

We house this players resolver in a resolvers folder which leaves our current folder structure like so:

Our GraphQL folder structure

Now our query_type.rb file looks a little leaner as we place in a new instance of our players resolver on line 17 below…

A little better

…but we still have that darn, unpleasant if/else statement in our players resolver.

To if/else, So Long Old Friend

Here is an example of a pattern we use to get rid of some of the if/else statements that you may see in some of your resolve lambdas or even your Rails controllers. ::shudder::

That’s so Raven, I mean meta

We create a method (line 9 above) that will iterate over a list of possible arguments (:ids, :team_id, :position_type) and direct it to the right query-handling method if said argument is present. In this example, if it does not contain an argument we expect, we end up grabbing all of the instances of the model (i.e. Player.all).

Some advantages of this pattern:

  • clarity on what will happen when you receive a certain argument
  • single responsibility for each argument method
  • ease of adding additional arguments
  • ease of unit testing the resolver

An example of a resolver test would be (this resolver could be tested like this before we broke up the if/else statement as well):

A test for passing a team_id argument

One Last Change, Please

Ok, one other thing we do here to keep our query_type.rb organized. We will look at the result first and then look at how we got there.

Using a FieldCombiner in your query_type.rb

With only one <model>QueryType, it doesn’t make much sense to do this, but on a more sizable app, with tens, hundreds, dare I say thousands of these <model>QueryTypes, this structure would help.

To implement this change, we’ll store our player and players fields into one <model>QueryType file…

PlayerQueryType

…and create something we call a FieldCombiner class, whose combine method will iterate through the list of QueryTypes, which are GraphQL::ObjectTypes., and call fields on each one and merge the results into one hash.

What our FieldCombiner looks like
Our final GraphQL folder structure

And That’s It!

This structure helps us easily navigate and build upon our GraphQL codebase as we leave the RESTful world behind. We are working on making these resolvers even easier to use and even more Rails-y, so expect more on the topic. Please comment below if you have any questions, suggestions or trolling impulses. I would love to hear what y’all think, and I hope this helps you as well.

That was easy!

--

--

Steve Aragon
AlphaSights Engineering

Left NYC. Now in Rip City. Devs for food and fun. Wannabe Chaos Monkey.