# GraphQL on Rails: From zero to the first query

> A hitchhiker’s guide to developing GraphQL applications with Rails and React/Apollo. Part 1: how to make your first query to your own GraphQL server

- Date: 2019-06-04T00:00:00.000Z
- Authors: Dmitry Tsepelev, Polina Gurtovaya
- Categories: 
- URL: https://evilmartians.com/chronicles/graphql-on-rails-1-from-zero-to-the-first-query

---

A hitchhiker’s guide to developing GraphQL applications with Rails on the backend side and React/Apollo on the frontend side. Follow this multi-part tutorial to learn both the basics and the advanced topics by example and feel the power of this modern technology.

[GraphQL](https://graphql.org) is one of those new shiny things we’ve been seeing here, there and everywhere: [blog posts](https://evilmartians.com/chronicles/exposing-permissions-in-graphql-apis-with-action-policy), [conferences](https://www.graphqlconf.org), [podcasts](https://graphqlradio.com), maybe, even newspapers. It sounds like you should hurry up and start rewriting your application in GraphQL instead of REST as soon as possible, right? Not exactly. Remember: there is no silver bullet. It’s essential to understand the pros and cons of the technology before making a paradigm-shift decision.

*Read also Evil Martians' article*: https://evilmartians.com/chronicles/exposing-permissions-in-graphql-apis-with-action-policy

In this series, we’re going to walk you through a no-frills guide to the development of GraphQL applications, talking about not only its advantages but also its caveats and pitfalls (and, of course, the ways to deal with them).

## GraphQL in a nutshell

According to the [specification](https://graphql.github.io/graphql-spec/), GraphQL is a *query language* and *runtime* (or *execution engine*). Query language, [by definition](https://en.wikipedia.org/wiki/Query_language), describes how to communicate with an information system. Runtime is responsible for fulfilling queries with data.

There are a lot of other query languages, for instance, SQL and XPath.

At the core of every GraphQL application lies a [*schema*](https://graphql.org/learn/schema/): it describes the underlying data in the form of a directed graph. The runtime must execute queries according to the schema (and some general rules from the specification). That means, every valid GraphQL server runs queries in the same manner and returns data in the same format for the same schema. In other words, the schema is everything clients should know about the API.

Here is an example of a simple GraphQL query:

```js
query getProduct($id: Int!) {
  product(id: $id) {
    id
    title
    manufacturer {
      name
    }
  }
}
```

Let’s dissect it line by line:

- We define a named query (`getProduct` is the operation name) accepting a single argument (`$id`). The operation name is optional, but it helps readability and could be used by frontend for caching.
- We “select” the `product` field from the “root” of the schema and pass the `$id` value as an argument.
- We describe the fields we want to fetch: in this case, we want to get the `id` and `title` of the product as well as the `name` of the manufacturer.

> Essentially, a query represents a sub-graph of the schema, which brings the first benefit of GraphQL—we can fetch only this data we need and all we need at once, in a single query.

This way, we solve one of the common problems of the traditional REST APIs—*overfetching*.

Check out [this Stack Overflow post](https://stackoverflow.com/questions/44564905/what-is-over-fetching-or-under-fetching) to learn more about both overfetching and underfetching.

Another noticeable feature of GraphQL schemas is they are *strongly* *typed*: both client and runtime ensure that the data passed is valid from the perspective of the application’s type system. For example, if someone mistakenly passes a string value as the `$id` to the query above, the client fails with the exception without even trying to perform a request.

And the last but not least bonus is a *schema* *introspection*: clients can learn the API from the schema itself, without any additional documentation sources.

There are plenty of tools to convert a schema into an interactive documentation website, standalone (e.g., [GraphiQL](https://github.com/graphql/graphiql) or [graphdoc](https://2fd.github.io/graphdoc)) and framework-specific (e.g., [Apollo DevTools](https://chrome.google.com/webstore/detail/apollo-client-developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm)).

We've just learned a bunch of theoretical aspects of GraphQL. Now it's time to do some coding exercises to make sure you won't forget everything tomorrow's morning.

## What are we going to build?

During this series, we will be building an application representing a “Martian Library”—a personal online collection of movies, books, and other art objects related to the Red Planet.

*Image: The application we are going to build*

For this tutorial, we’re going to use:

- Ruby 2.6 and Rails 6 ([release candidate is already here](https://evilmartians.com/chronicles/rails-6-b-sides-and-rarities)) for backend.
- Node.js 9+, React 16.3+, and Apollo (client version 2+) for frontend (and make sure you have yarn installed according to the [instruction](https://yarnpkg.com/en/docs/install#mac-stable)).

You can find the source code [here](https://github.com/evilmartians/chronicles-gql-martian-library/tree/part-1)—don't forget to run `bundle install && yarn install` before the first run. [`master` branch](https://github.com/evilmartians/chronicles-gql-martian-library) represents a current state of the project.

## Setting up a new Rails project

If at the time of reading this article Rails 6.0 hasn’t been released yet, you might need to install the release candidate first:

```bash
$ gem install rails --pre
$ rails -v
=> Rails 6.0.0.rc1
```

Now we’re ready to run this unexpectedly long `rails new` command:

```bash
$ rails new martian-library -d postgresql --skip-action-mailbox --skip-action-text --skip-spring --webpack=react -T --skip-turbolinks
```

We prefer *okonomi* to [*omakase*](https://dhh.dk/2012/rails-is-omakase.html): skip frameworks and libraries we don’t need, choose PostgreSQL as our database, preconfigure Webpacker to use React, and skip tests (don’t worry—we’ll add RSpec soon).

Before you start, it’s strongly recommended that you disable all the unnecessary generators in the  `config/application.rb`:

```ruby
config.generators do |g|
  g.test_framework  false
  g.stylesheets     false
  g.javascripts     false
  g.helper          false
  g.channel         assets: false
end
```

## Preparing the data model

We need at least two models to start:
- `Item` to describe  any entity (book, movie, etc.) that we want to store in the library
- `User` to represent the application user who can manage items in the collection.

Let’s generate them:

```bash
$ rails g model User first_name last_name email
$ rails g model Item title description:text image_url user:references
```

Don’t forget to add the `has_many :items` association to `app/models/user.rb`:

```ruby
# app/models/user.rb
class User < ApplicationRecord
  has_many :items, dependent: :destroy
end
```

Let’s add some pre-generated data to `db/seeds.rb`:

```ruby
# db/seeds.rb
john = User.create!(
  email: "john.doe@example.com",
  first_name: "John",
  last_name: "Doe"
)

jane = User.create!(
  email: "jane.doe@example.com",
  first_name: "Jane",
  last_name: "Doe"
)

Item.create!(
  [
    {
      title: "Martian Chronicles",
      description: "Cult book by Ray Bradbury",
      user: john,
      image_url: "https://upload.wikimedia.org/wikipedia/en/4/45/The-Martian-Chronicles.jpg"
    },
    {
      title: "The Martian",
      description: "Novel by Andy Weir about an astronaut stranded on Mars trying to survive",
      user: john,
      image_url: "https://upload.wikimedia.org/wikipedia/en/c/c3/The_Martian_2014.jpg"
    },
    {
      title: "Doom",
      description: "A group of Marines is sent to the red planet via an ancient " \
                   "Martian portal called the Ark to deal with an outbreak of a mutagenic virus",
      user: jane,
      image_url: "https://upload.wikimedia.org/wikipedia/en/5/57/Doom_cover_art.jpg"
    },
    {
      title: "Mars Attacks!",
      description: "Earth is invaded by Martians with unbeatable weapons and a cruel sense of humor",
      user: jane,
      image_url: "https://upload.wikimedia.org/wikipedia/en/b/bd/Mars_attacks_ver1.jpg"
    }
  ]
)
```

Finally, we’re ready to initialize our database:

```bash
$ rails db:create db:migrate db:seed
```

Now that we’ve put some information into our system, let’s add a way to access it!

## Adding a GraphQL endpoint

For crafting our GraphQL API, we will use the [graphql-ruby](https://github.com/rmosolgo/graphql-ruby) gem:

```bash
# First, add it to the Gemfile
$ bundle add graphql --version="~> 1.9"
# Then, run the generator
$ rails generate graphql:install
```

You might be surprised by the number of files a minimal `graphql-ruby` application requires: this boilerplate is the price we pay for all the goodies we described above.

*Image: The result of executing `graphql:install` generator*

First of all, let’s take a look at the schema, `martian_library_schema.rb`:

```ruby
# app/graphql/martian_library_schema.rb
class MartianLibrarySchema < GraphQL::Schema
  query(Types::QueryType)
  mutation(Types::MutationType)
end
```

The schema declares that all the queries should go to `Types::QueryType` while mutations should go to `Types::MutationType`. We’re going to dig deeper into mutations in the second part of the series; the goal of this article is to learn how to write and execute queries. Thus, let’s open the `types/query_type.rb` class—it is an entry point for all the queries. What’s inside?

```ruby
# app/graphql/types/query_type.rb
module Types
  class QueryType < Types::BaseObject
    # Add root-level fields here.
    # They will be entry points for queries on your schema.

    # TODO: remove me
    field :test_field, String, null: false,
      description: "An example field added by the generator"
    def test_field
      "Hello World!"
    end
  end
end
```

It turns out that `QueryType` is just a regular type: it inherits from the `Types::BaseObject` (which we will use as a base class for all types), and it has *field* definitions—the nodes of our data graph. The only thing that makes `QueryType` different is that GraphQL requires this type to exist (while *mutation* and *subscription* types are optional).

Have noticed that the code above is actually a “hello world” app? Before going further (and boring you with by the amount of code), we’d like to show you how to get this “hello world” in your browser.

Let’s see what has been added to the `config/routes.rb` file by the generator:

```ruby
# config/routes.rb
Rails.application.routes.draw do
  mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/graphql" if Rails.env.development?
  post "/graphql", to: "graphql#execute"
end
```

Mounting `GraphiQL::Rails::Engine` allows us to test our queries and mutations using a web interface called [GraphiQL](https://github.com/graphql/graphiql). As we discussed in the introduction, the schema can be inspected, and GraphiQL uses this feature to build interactive documentation for us. It's time to give it a shot!

```bash
# Let's run a Rails web server
$ rails s
```

Open up [http://localhost:3000/graphiql](http://localhost:3000/graphiql) in the browser:

*Image: GraphiQL UI*

In the left pane, you can type a query to execute, then click the “play” button (or hit *Ctrl/Cmd+Enter*) and get the response in the right pane. By clicking the “Docs” link at the right top corner, you can explore your schema.

Let’s take a look at our logs—we want to know what happens when we click the _execute_ button.

*Image: Execution logs*

Requests are sent to `GraphqlController`, which has also been added to the application by the `graphql` gem generator.

GraphQL is transport-agnostic, but most implementations, including `ruby-graphql`, use HTTP POST requests.

Take a look at the `GraphqlController#execute` action:

```ruby
# app/controllers/graphql_controller.rb
def execute
  variables = ensure_hash(params[:variables])
  query = params[:query]
  operation_name = params[:operationName]
  context = {
    # Query context goes here, for example:
    # current_user: current_user,
  }
  result = GraphqlSchema.execute(
    query,
    variables: variables,
    context: context,
    operation_name: operation_name
  )
  render json: result
rescue StandardError => e
  raise e unless Rails.env.development?

  handle_error_in_development e
end
```

This action calls the `GraphqlSchema#execute` method with the following parameters:

- `query` and `variables` represent a query string and arguments sent by a client respectively;
- `context` is an arbitrary hash, which will be available during the query execution everywhere;
- `operation_name` picks a named operation from the incoming request to execute (could be empty).

All the magic happens inside this method: it parses the query, detects all the types that should be used for building the response, and resolves all the requested fields. The only thing we need to do is to define the types and declare how fields should be resolved.

## What’s in the Martian Library?

Let’s move from “hello world” to something real: remove the example contents from `Types::QueryType` and register a field called `:items` which will return all the items from the library. We also need to add a resolver method for this field (the resolver method name must match the field name):

```ruby
# app/graphql/types/query_type.rb
module Types
  class QueryType < Types::BaseObject
    field :items,
          [Types::ItemType],
          null: false,
          description: "Returns a list of items in the martian library"

    def items
      Item.all
    end
  end
end
```

Each field definition contains a name, a result type, and options; `:null` is required and must be set to either `true` or `false`. We also define optional `:description`—it’s a good practice to add a human-readable message to a field: it will be automatically added to documentation providing more context to developers. The array notation for the result type, `[Types::ItemType]`, means that the field value must be an array and each element of this array must be represented using the `Types::ItemType` type.

But we haven’t defined `ItemType` yet, right? Hopefully, the `graphql` gem will give us a handy generator:

```bash
$ rails g graphql:object item
```

Now we can modify the newly created `app/graphql/types/item_type.rb` to our liking.

```ruby
# app/graphql/types/item_type.rb
module Types
  class ItemType < Types::BaseObject
    field :id, ID, null: false
    field :title, String, null: false
    field :description, String, null: true
    field :image_url, String, null: true
  end
end
```

As you can see, we’re exposing three fields in `ItemType`:

You may use UUID as a primary key in your table if you are worried about exposing sequential IDs, but let's go with the easy way now.

- non-nullable fields `id` and `title`
- a nullable field `description`

Our execution engine resolves fields using the following algorithm (slightly simplified):

- First, it looks for the method with the same name defined in the type class itself (like we did earlier in the `QueryType` for `items`); we can access the object being resolved using the `object` method.
- If no such method defined, it tries to call the method with the same name on the `object` itself.

We do not define any methods in our type class; thus, we assume that the underlying implements all the fields’ methods.

Go back to [http://localhost:3000/graphiql](http://localhost:3000/graphiql), execute the following query, and make sure that you get the list of all items in response:

```js
{
  items {
    id
    title
    description
  }
}
```

So far, we haven’t added any functionality that leverages the power of graphs—our current graph's depth is one. Let’s grow the graph by adding a non-primitive node to `ItemType`, for example, a `user` field to represent the user who created the item:

```ruby
# app/graphql/types/item_type.rb
module Types
  class ItemType < Types::BaseObject
    # ...
    field :user, Types::UserType, null: false
  end
end
```

Let’s repeat the same generator spell to create a new type class:

```bash
$ rails g graphql:object user
```

This time we also want to add a computed field—`full_name`:

```ruby
# app/graphql/types/user_type.rb
module Types
  class UserType < Types::BaseObject
    field :id, ID, null: false
    field :email, String, null: false
    field :full_name, String, null: false

    def full_name
      # `object` references the user instance
      [object.first_name, object.last_name].compact.join(" ")
    end
  end
end
```

Let’s transform our query to fetch users along with items:

```js
{
  items {
    id
    title
    user {
      id
      email
    }
  }
}
```

At this point, we’re ready to move our attention from the backend side to the frontend side. Let’s build a client for this API!

## Configuring the frontend application

As we already mentioned, we recommend you install the [Apollo](https://www.apollographql.com/docs/react/) framework for dealing with GraphQL client-side.

If you’re using Google Chrome, mind installing the Apollo [extension](https://chrome.google.com/webstore/detail/apollo-client-developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm).

To get the ball rolling, we need to install all the required dependencies:

```bash
$ yarn add apollo-client apollo-cache-inmemory apollo-link-http apollo-link-error apollo-link graphql graphql-tag react-apollo
```

Let’s take a look at some of the installed packages:

We didn’t include any package-adding types to JS ([TypeScript](http://www.typescriptlang.org) or [Flow](https://flow.org)) so as not to make this tutorial too complicated. In practice, using typed JS with GraphQL makes a lot of sense since we already have a types system. For instance, [apollo-codegen](https://github.com/apollographql/apollo-tooling) can generate type signatures automatically.

- We use `graphql-tag` to build our first queries.
- `apollo-client` is a generic framework-agnostic package for performing and caching GraphQL requests.
- `apollo-cache-inmemory` is a storage implementation for Apollo cache.
- `react-apollo` contains a set of React components for displaying data.
- `apollo-link` and other *links* implement a middleware pattern for `apollo-client` operations (you can find further details [here](https://www.apollographql.com/docs/link/overview.html)).

Now we need to create an entry point for our frontend application. Remove `hello_react.jsx` from the `packs` folder and add `index.js`:

```bash
$ rm app/javascript/packs/hello_react.jsx && touch app/javascript/packs/index.js
```

For the sake of debugging, it’s good enough to stay with the following content:

```js
// app/javascript/packs/index.js
console.log('👻');
```

Let’s generate a controller to serve our frontend application:

```bash
$ rails g controller Library index --skip-routes
```

Update `app/views/library/index.html.erb` to contain the React root element and a link to our *pack*:

```erb
<!-- app/views/library/index.html.erb -->

<%= javascript_pack_tag 'index' %>
```

Finally, let’s register a new route in the `config/routes.rb`:

```ruby
# config/routes.rb
root 'library#index'
```

Restart your Rails server and make sure you see the ghost in the browser console. Don't be scared.

## Configuring Apollo

Create a file for storing our application’s Apollo config:

```bash
$ mkdir -p app/javascript/utils && touch app/javascript/utils/apollo.js
```

In this file we want to configure the two core entities of the Apollo application, the client and the cache (or more precisely, the functions to create both):

```js
// app/javascript/utils/apollo.js

// client
import { ApolloClient } from 'apollo-client';
// cache
import { InMemoryCache } from 'apollo-cache-inmemory';
// links
import { HttpLink } from 'apollo-link-http';
import { onError } from 'apollo-link-error';
import { ApolloLink, Observable } from 'apollo-link';
export const createCache = () => {
  const cache = new InMemoryCache();
  if (process.env.NODE_ENV === 'development') {
    window.secretVariableToStoreCache = cache;
  }
  return cache;
};
```

Let’s take a second and look at how cache works.

Caching is one of the most powerful features of Apollo. Sometimes it becomes overpowering, and you might prefer a more straightforward solution. In any case, it's worth learning how it works. Find more details about how Apollo caching works [here](https://www.apollographql.com/docs/react/advanced/caching.html).

Each query response is put into the cache (the corresponding request is used to generate the cache key). Before making a request, `apollo-client` ensures that the response hasn’t been cached yet, and if it has been—the request is not performed. This behavior is configurable: for instance, we can turn off caching for a particular request or ask the client to look for a cache entry of a different query.

One important thing we need to know about the cache mechanism for this tutorial is that, by default, a cache key is a concatenation of the object `id` and `__typename`. Thus, fetching the same object twice would result only in one request.

Back to coding. Since we use HTTP POST as a transport, we need to attach a proper CSRF token to every request to pass the [forgery protection check](https://guides.rubyonrails.org/security.html#cross-site-request-forgery-csrf) in the Rails app. We can grab it from `meta[name="csrf-token"]` (which is generated by `<%= csrf_meta_tags %>`):

```js
// app/javascript/utils/apollo.js
// ...
// getToken from meta tags
const getToken = () =>
  document.querySelector('meta[name="csrf-token"]').getAttribute('content');
const token = getToken();
const setTokenForOperation = async operation =>
  operation.setContext({
    headers: {
      'X-CSRF-Token': token,
    },
  });
// link with token
const createLinkWithToken = () =>
  new ApolloLink(
    (operation, forward) =>
      new Observable(observer => {
        let handle;
        Promise.resolve(operation)
          .then(setTokenForOperation)
          .then(() => {
            handle = forward(operation).subscribe({
              next: observer.next.bind(observer),
              error: observer.error.bind(observer),
              complete: observer.complete.bind(observer),
            });
          })
          .catch(observer.error.bind(observer));
        return () => {
          if (handle) handle.unsubscribe();
        };
      })
  );
```

Let’s look at how we can log errors:

```js
// app/javascript/utils/apollo.js
//...
// log erors
const logError = (error) => console.error(error);
// create error link
const createErrorLink = () => onError(({ graphQLErrors, networkError, operation }) => {
  if (graphQLErrors) {
    logError('GraphQL - Error', {
      errors: graphQLErrors,
      operationName: operation.operationName,
      variables: operation.variables,
    });
  }
  if (networkError) {
    logError('GraphQL - NetworkError', networkError);
  }
})
```

In production, it makes more sense to use an exception tracking service (e.g., Sentry or Honeybadger): just override the `logError` function to send errors to the external system.

We’re almost there—let’s tell the client about the endpoint for making queries:

```js
// app/javascript/utils/apollo.js
//...
// http link
const createHttpLink = () => new HttpLink({
  uri: '/graphql',
  credentials: 'include',
})
```

Finally, we’re ready to create an Apollo client instance:

```js
// app/javascript/utils/apollo.js
//...
export const createClient = (cache, requestLink) => {
  return new ApolloClient({
    link: ApolloLink.from([
      createErrorLink(),
      createLinkWithToken(),
      createHttpLink(),
    ]),
    cache,
  });
};
```

## The very first query

We’re going to use a [provider pattern](https://reactjs.org/docs/context.html#contextprovider) to pass the client instances to React components:

```bash
$ mkdir -p app/javascript/components/Provider && touch app/javascript/components/Provider/index.js
```

It’s the first time we are using an `ApolloProvider` component from the `react-apollo` library:

```js
// app/javascript/components/Provider/index.js
import React from 'react';
import { ApolloProvider } from 'react-apollo';
import { createCache, createClient } from '../../utils/apollo';

export default ({ children }) => (

    {children}

);
```

Let’s change our `index.js` to use the newly created provider:

```js
// app/javascript/packs/index.js
import React from 'react';
import { render } from 'react-dom';
import Provider from '../components/Provider';

render(👻, document.querySelector('#root'));
```

If you use `Webpacker v3` you may need to import `babel-polyfill` to use all the cool JavaScript tricks like async/await. Don’t worry about the polyfill’s size; `babel-preset-env` will remove everything you don’t need.

Let’s create a `Library` component to display the list of items on the page:

```bash
$ mkdir -p app/javascript/components/Library && touch app/javascript/components/Library/index.js
```

We’re going to use the `Query` component from `react-apollo`, which accepts the `query` string as a property to fetch the data on mount:

```js
// app/javascript/components/Library/index.js
import React from 'react';
import { Query } from 'react-apollo';
import gql from 'graphql-tag';

const LibraryQuery = gql`
  {
    items {
      id
      title
      user {
        email
      }
    }
  }
`;

export default () => (

    {({ data, loading }) => (

        {loading
          ? 'loading...'
          : data.items.map(({ title, id, user }) => (

                <b>{title}</b> {user ? `added by ${user.email}` : null}

            ))}

    )}

);
```

We can access the loading state and loaded data through the corresponding `loading` and `data` properties (passed using a so-called [render-props pattern](https://reactjs.org/docs/render-props.html)).

Don’t forget to add the component to the main page:

```js
// app/javascript/packs/index.js
import React from 'react';
import { render } from 'react-dom';
import Provider from '../components/Provider';
import Library from '../components/Library';

render(

  ,
  document.querySelector('#root')
);
```

If you reload the page you should see the list of items with emails of users who added them:

*Image: List of items with emails of users*

Congratulations! You’ve just made the very first step towards GraphQL happiness!

## …And the very first problem

Everything seems to work fine, but let’s take a look at our server logs:

*Image: N + 1*

The SQL query `SELECT * FROM users WHERE id = ?` is executed **four times**, which means that we hit the famous *N+1 problem*—server makes a query for each item in the collection to get the corresponding user info.

Before fixing the problem, we need to make sure that it’s safe to make code modifications without breaking anything—let’s write some tests!

## Writing some specs

Now it’s time to install and configure RSpec, or more precisely, the `rspec-rails` gem:

Since we’re running on the edge, we need the upcoming version of the gem.

```bash
# Add gem to the Gemfile
$ bundle add rspec-rails --version="4.0.0.beta2" --group="development,test"
# Generate the initial configuration
$ rails generate rspec:install
```

To make it easier to generate data for tests let’s install [factory_bot](https://github.com/thoughtbot/factory_bot):

```bash
$ bundle add factory_bot_rails --version="~> 5.0" --group="development,test"
```

Make factory methods (`create`, `build`, etc.) globally visible in tests by adding `config.include FactoryBot::Syntax::Methods` to the `rails_helper.rb`.

Since we created our models before adding Factory Bot, we should generate our factories manually. Let’s create a single file, `spec/factories.rb`, for that:

```ruby
# spec/factories.rb
FactoryBot.define do
  factory :user do
    # Use sequence to make sure that the value is unique
    sequence(:email) { |n| "user-#{n}@example.com" }
  end

  factory :item do
    sequence(:title) { |n| "item-#{n}" }
    user
  end
end
```

Now we are ready to write our first test. Let’s create a spec file for `QueryType`:

```bash
$ mkdir -p spec/graphql/types
$ touch spec/graphql/types/query_type_spec.rb
```

The simplest query test looks like this:

```ruby
# spec/graphql/types/query_type_spec.rb
require "rails_helper"

RSpec.describe Types::QueryType do
  describe "items" do
    let!(:items) { create_pair(:item) }

    let(:query) do
      %(query {
        items {
          title
        }
      })
    end

    subject(:result) do
      MartianLibrarySchema.execute(query).as_json
    end

    it "returns all items" do
      expect(result.dig("data", "items")).to match_array(
        items.map { |item| { "title" => item.title } }
      )
    end
  end
end
```

First, we create a pair of items in our database. Then, we define the query under test and the subject (`result`) by calling the `GraphqlSchema.execute` method. Remember, we had a similar line in the `GraphqlController#execute`?

Testing GraphQL might feel repetitive. Should it happen to you—consider using fixtures and the [fixturama](https://github.com/nepalez/fixturama) gem.
*Read also Evil Martians' article*: https://evilmartians.com/chronicles/a-fixture-based-approach-to-interface-testing-in-rails

This example is very straightforward: we’re not passing either `variables` or `context` to the `execute` call, though we definitely can do that if needed.

Now we’re confident enough to fix “the bug”—the N+1 problem!

## GraphQL vs. N+1 problem

The easiest way to avoid N+1 queries is to use [eager loading](https://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations). In our case, we need to preload users when making a query to fetch items in `QueryType`:

```ruby
# /app/graphql/types/query_type.rb
module Types
  class QueryType < Types::BaseObject
    # ...

    def items
      Item.preload(:user)
    end
  end
end
```

This solution can help in simple situations, but it's not very efficient: the following code preloads users even if the client does not need them, e.g.:

```js
items {
  title
}
```

Discussing other ways to solve the N+1 problem is worthy of a dedicated post and out of this tutorial’s scope.
Most of the solutions fit the following two groups:

Learn how to solve the N+1 problem using batch loading by example:
*Read also Evil Martians' article*: https://evilmartians.com/chronicles/active-storage-meets-graphql-direct-uploads

- lazy eager loading (e.g., using the [ar_lazy_preload](https://github.com/DmitryTsepelev/ar_lazy_preload) gem)
- batch loading (e.g., using the [graphql-batch](https://github.com/Shopify/graphql-batch) gem)

---

That’s all for today! We learned a lot about GraphQL, completed all the routine work of configuring the backend and frontend applications, made the first query, and even found and fixed the first bug. And that's just a tiny step (despite the size of the article) in our journey. We'll come back shortly and unveil how to manipulate data using GraphQL mutations and keep it up-to-date with subscriptions. Stay tuned!

*Read also Evil Martians' article*: https://evilmartians.com/chronicles/graphql-on-rails-2-updating-the-data

---

This article was written by [Evil Martians](https://evilmartians.com), a product development consultancy trusted by teams from early-stage startups to public companies. If you're working through a hard problem, [we can help](https://evilmartians.com/contact-us)
