GraphQL Basics
Tags: ruby, rails, graphql
Published: 2020-06-13 21:05:49

GraphQL is a relatively new query language originally developed by [Facebook in 2012][foundation]. The primary goal of GraphQL is to reduce the amount of unnecessary data that an API query returns.

GraphQL allows developers to retrieve associated objects in a single query. REST APIs, on the other hand would require multiple queries for the same data.

Writing GraphQL queries requires a little more of a learning curve than REST queries, but once learned, GraphQL is fairly easy to understand.

I’ve decided to split what was originally planned to be one article into two, because I think it will be easier to process everything in smaller chunks.

# GraphQL Basics
Before jumping right in to writing code with GraphQL, it is critical to understand a little bit about how it works in the background.

GraphQL, like REST can be implemented in any programming language, and there are already libraries in a [bunch of languages][implementations] to help get new users started. In [part 2][part2] of this series, we installed the ruby implementation of GraphQL

One of the key features of GraphQL is its [type system][typesystem]. For those of us who don’t have CS degrees, a type is essentially a description of what kinds of data are represented by the type's name.

For example: a common type is the integer type. The integer type only allows instances of it to contain positive or negative whole numbers. Another common type is the string type. Strings allow any sequence of characters to be contained within instances of strings. For more details of what data types are and how they are used, checkout the [Wikipedia article on data types][datatypes].

GraphQL has two fundamental kinds of types: object types which we will use to build queries, and scalar types which represent concrete data. The uses of these two different types should become clearer as we progress.

# Scalar Types
GraphQL has five built-in scalar types. We will use these five types when we  start building our object types later. The five built-in types are: `String`, `Int`, `Float`, `Boolean`, and `ID`. 

`String`s represent any kind of string data, `Int`s represent positive and negative whole numbers, `Float`s represent any positive or negative real number, including those with decimal points, `Boolean`s represent true or false values, and `ID`s represent the id of an object in the underlying database system.

# Object Types
Object types are mostly developer defined and are composed of any combination of the five scalar types along with other object types.

Object types are what we will focus on, because the object types we build near the end will allow us to query the backend using GraphQL. Essentially, we will simply translate the models defined in part 2 into GraphQL types.

# GraphQL Queries
Queries are the glue of GraphQL that bind the frontend to the backend. Take a look at a basic GraphQL query:
```
query {
    users {
        id
        name
        username
    }
}
```
Here is a breakdown of the parts of the query:
![GraphQL Query breakdown](https://dev-to-uploads.s3.amazonaws.com/i/bkx4cuvzh4k2uuxd5c16.png)

Suppose we wanted to get the titles of all the topics this user has created too, all we have to do is add the following:
```
query {
    users {
        id
        name
        username
        topics {
            title
        }
    }
}
```

The result of this query would include all of the titles of the topics each user has created. When writing GraphQL queries, remember that all queried objects must resolve to scalar types at some point.

# Building our GraphQL schema
The GraphQL gem provides a bunch of useful generators to help us build object types quickly.

Run the following command in the project's root directory:
```bash
rails g graphql:object User username:String name:String email:String id:ID comments:[Reply] likes:[Like] topics:[Topic]
```
The `User` argument is the name of the new GraphQL type. Each of the other arguments follows the format `<field_name>:<field_type>`. So, `username:String` means add a field named username with a type of String. These fields map to the attributes with the same names on our models. Fields like `comments:[Reply]` tell graphql three things:

1. Make a field named `comments`.
2. Make the new field a list. The brackets around the type tell GraphQL to use an array.
3. For the List's type, use the `Reply` type.

We have not made the `Reply` type yet so go ahead and run the following commands to finish building the base types:
```bash
rails g graphql:object Topic title:String content:String id:ID user:User likes:[Like] replies:[Reply]
rails g graphql:object Like user:User post:Post id:ID
rails g graphql:object Reply content:String id:ID user:User post:Post
```
In order to support the polymorphic associations we set up in part 2, we will need to create the union type Post. A union type is a type that can represent one of several different types. Run the following command:
```bash
rails g graphql:union Post Reply Topic
```
There seems to be a bug with the union type generator, so it might be necessary to alter `post_type` a little:
```ruby
# app/graphql/types/post_type.rb
module Types
  class PostType < Types::BaseUnion
    # Instead of the following line of code you may see:
    # possible_types [Types::ReplyType, Types::TopicType]
    # If you do, this is a bug. Remove the brackets to fix it.
    possible_types Types::ReplyType, Types::TopicType
  end
end
```
Now that we have generated all the base types, we need to make them queryable. Open up `query_type.rb`, remove the default `test_field` and add the following code:
```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.

    field :users, [Types::UserType], null: false, description: 'Returns all the users'

    def users
      User.all
    end

    field :topics, [Types::TopicType], null: false, description: 'Returns all the topics'

    def topics
      Topic.all
    end

    field :topic, Types::TopicType, null: true do
      argument :id, ID, required: true
    end

    def topic(id:)
      Topic.find_by(id: id)
    end

    field :user, Types::UserType, null: true do
      argument :id, ID, required: true
    end

    def user(id:)
      User.find_by(id: id)
    end
  end
end
```
The `field` shortcuts here are very similar to those that the commands generated. The first argument (e.g. `:users`) is the name of the field, the second argument is the type of the field, the third determines whether the return value can be null, and the last is a description of the field. The `argument` lines declare that the field requires an argument, which we will cover in more detail later in the series.

# Running Test Queries
If you want to test our new GraphQL back end, you can do so using either [GraphiQL][graphiql] or [Postman][postman].

GraphQL is a very powerful library that can greatly reduce API development time. GraphQL takes a little more work to understand than REST APIs, but I find the reward well worth the effort. Thank you for reading!

As usual, the code is available in the [GitHub repo][code]

[foundation]: https://foundation.graphql.org/
[typesystem]: https://graphql.org/learn/schema/#type-system
[implementations]: https://graphql.org/code/
[part2]: https://dev.to/speratus/basic-models-and-polymorphic-associations-223o
[datatypes]: https://en.wikipedia.org/wiki/Data_type
[graphiql]: https://www.electronjs.org/apps/graphiql
[postman]: https://www.postman.com/
[code]: https://github.com/speratus/miniforum/tree/part3-graphql-1