GraphQL basics for Rails applications

Mateo mojica
9 min readFeb 9, 2024
Photo by Evaldas Grižas on Unsplash

GraphQL is a technology that is being used more and more to create APIs due to its flexibility and speed. It was created by Facebook in 2012 as a response to the “slowness” of REST and open-sourced in 2015 and since then it has only risen in popularity. In this article, we are going to explore what is GraphQL and how to implement it in a Ruby on Rails application so you can start using it right now, so let’s begin.

GraphQL is a query language for your API and a server-side runtime for executing queries using a type system you define for your data. GraphQL isn’t tied to any specific database or storage engine and is instead backed by your existing code and data.

A GraphQL service is created by defining types and fields on those types and then providing functions for each field on each type. After a GraphQL service is running (typically at a URL on a web service), it can receive GraphQL queries to validate and execute. The service first checks a query to ensure it only refers to the types and fields defined and then runs the provided functions to produce a result.

Photo by Mateusz Wacławek on Unsplash

To understand it a little more let’s compare it to REST which is the most used standard for building APIs. GraphQL works over HTTP and many other protocols in the same way REST does, but there are many differences between the two. GraphQL uses a single endpoint to process all the requests no matter what type they are, this means no additional structure is needed to create the API. REST by definition is a standard that encourages multiple requests to get all the needed resources, GraphQL works under the no over/under-fetching premise, just get exactly the information you need with one request, this reduces the network calls significantly because it bundles all the resources together with fewer calls. One thing that plays against GraqphQL is that all the responses have a status of 200, you can’t use statuses to indicate actions that you need to take. Later on in this article, we are going to see a way to add errors to a GraphQL response to mitigate this issue.

Now let’s dive into some terminology and definitions of the elements that are part of GraphQL. The most important one is the query. A query is a way to ask the server for the needed data, in other words, read data from the API. Queries leverage the flexibility that GraphQL has, allowing you to ask only for the fields that you want instead of the whole data, making requests smaller and faster. Also gives you the ability to use fragments to ask for common fields across queries and also variables to make the queries dynamic.

Resolver for the single price field

Another important element of GraphQL is the mutation. A mutation is the way to change, create, or destroy data in GraphQL. A mutation tells the server that we need to do an update operation on an existing record or if the record doesn’t exist it has to be created. Mutations can also delete records, giving GraphQL the full CRUD functionality for APIs.

Now we are going to get into how the request gets processed. For this, we use what is called a resolver. Resolvers are the way GraphQL knows how to get the data for the query requested. In simple terms, it is a function that makes the necessary operations to return the requested data. There are two ways of using resolvers, the first one is to do it directly inside the query type file, the way that works is that you declare a field with the same name as the query(operation) and define the description, return type, and arguments that it is going to use, after that you define a method that has the same name as the field and in it you put all the business logic to fetch the data. Resolvers can also be separated from the query file into another file to make it easier to go through it, this can be done by just adding the resolver argument to the field, and indicating the class that is going to resolve that field. That class will have to define all the arguments that it will receive and the return type for the result, you can also put a description to explain the resolver but that is optional, it also needs a resolve method that is the one that is going to have all the business logic. This way your code will be a lot more organized and easier to read for everybody working on it.

Later we are going to see how to do that in Rails, but first, we have to set up GraphQL in our application to do this, you have to add the gem into your project’s gemfile, run the bundle install command to include it into your project, and then run the rails generate graphql:install command to add the necessary files in the application. If you are starting a new project from scratch the application will create the required files for you every time you create a new model. But the most likely scenario is that you are adding it to an existing project, in that case, you can create the GraphQL files for existing models using the rails generate graphql:object <model>, this will generate the files for that specific model.

Folder structure for a GraphQL project

Now to test if the API is responding we will need to have a way to send requests to the server, and luckily for us Postman recently added support for a variety of request types on their application, including GraphQL. To set them up is very similar to an HTTP request, you have to type the URL where the server receives all the GraphQL requests. You also have your Query area where you create the queries that you want, and if you have your files correctly set you also have an Explorer pane that has all the available queries and the schemas that they handle, from there you can auto-create a query by just checking the one you are interested in. You also have a variables section in the Query panel so you can declare the variables in JSON format to get them closer to what you will use in the application. On top of all that you have all the other tabs that are used to select the type of authorization and also a tab to add headers if you need to do so. Remember that for the auto-populate features to work the server has to be up.

Query request using Postman

Now that everything is ready inside the project we can start adding functionality to build our GraphQL API. The first thing is to build the queries to read data, this is done in the query type. The query type is a file that is inside the types folder of the GrapQL section for the application and it is where all the root-level fields are defined and resolved. A root-level field does not belong to anything else, meaning that it can’t be resolved anywhere else in the application, one good example of this type of field is the one that returns all the models available, those models belong to the application, and nothing else, so they have to be resolved in the “root query” as a root level field.

In the query type file, any method that has the same name as a field is the one that is going to be the resolver for that field as we saw earlier or you can also point to the class that is going to resolve it. Root-level fields can also receive information in the way of arguments from the request, to enable these arguments the definition of the field has to be transformed into a block to define them or define them in the resolver file.

One thing to take into account is that the notation for the field names is snake case (the same as rails) but when making the request it uses camel case (the same as JSON), the transformation between camel case and snake case and vice versa is handled by rails by default, but if you need a special transformation it can be modified as well.

Query type with resolvers defined in both ways

Another important part of GraphQL functionality is the context, this is information that is passed down from the controller into the fields and it is defined in the GraphQL controller for the application and is going to be the same for all the fields. The information that is inside the context is the one deemed important by the developers, one example of information passed through the context is the current user.

GraphQL also uses Types, these define the schema that the data must have to be used. Every field must have a type assigned to it, and it can be one of the default ones or custom ones created for models or other objects. For every field in a type (custom or query), there is a directive that indicates if it is required. Required fields are a way to tell GraphQL that a field can’t return null, meaning that it has to be populated before sending the response back. This is indicated by the null directive on each field. If it says null: false it means the field needs to have information and if you request that field and for some reason is null, GraphQL will raise an error.

You can also have custom fields in those types. Custom fields are the ones that are not an attribute of the model or a key in a hash and need additional processing to be resolved. There are two ways to add custom fields, one is to define it in a model with a method that has the processing logic and use it as a resolver for that field, this will allow us not only to use it for the response for GraphQL but also in any other part of the application if needed. For using it in this way we just need to add it to the type with the same name it has on the model. The second way is to define it into the type file itself as you would for a root-level field in the query type, this keeps together all the logic in one file but has the disadvantage of not being able to access that method from other parts of the application. Which one you choose, as always, depends on the implementation that you need or on the standards of the team you are working on.

One important thing to remember is that GraphQL has nine scalar types defined by the library but you can create your own types to fit your application’s needs, but eventually, everything will get translated into those main scalar types.

In the same way we created queries to retrieve data from the API, we can create mutations to transform data in the API. For this, we use the mutation type and define fields that are going to be the names of the operations performed on the data.

Mutation to create a category with error handling

For handling errors GraphQL doesn’t have a native way to handle errors, so one way to handle them is to create an error type and an error field for a specific type and we fill it with the errors that the application will throw.

Now you know what are the terms that GraphQL uses and how to use them in a Rails application, this is enough to get you started on your GraphQL journey. Thank you for reading this article and I hope it was helpful, if you liked it give it a clap. I also encourage you to check out all my other articles and consider following me to get new articles that I might create in the future.

References

--

--