Back to home

Setting Up A Base GraphQL Server And GraphiQL With Rails 7 main image

Setting Up A Base GraphQL Server And GraphiQL With Rails 7

This post will demonstrate a basic example of setting up a basic GraphQL server with the graphql-ruby gem.

The project itself will consist of a GraphQL schema that will demonstrate basic relationship between two models, Post and Comment, where each Post has a one-to-many relationship with the Comment entity.

Source code can be found here

Prerequisites

  1. Basic familiarity with setting up a new Rails project.
  2. A rudimentary understanding of GraphQL. I will mainly be operating a high-level of getting it working without explaining the queries.

Getting started

We will use Rails to initialize the project demo-graphql-server, adding the necessary GraphQL gems and then creating some base models and GraphQL objects:

# Create a new rails project $ rails new demo-graphql-server $ cd demo-graphql-server # Add the required gems $ bundler add graphql graphiql-rails # Setup our base GraphQL files $ bin/rails g graphql:install # Create our models $ bin/rails g model Post title rating $ bin/rails g model Comment body post:references # Make your first object type $ bin/rails g graphql:object Post title:String rating:Int comments:[Comment] $ bin/rails g graphql:object Comment body:String post:Post

Note: I am using Rails 7.x for this blog post.

The above does the following:

  1. Create a new Rails project demo-graphql-server.
  2. Add the required gems graphql and graphiql-rails to the project.
  3. Create the base GraphQL files with graphql:install generator that was installed.
  4. Create the models Post and Comment.
  5. Create the GraphQL objects Post and Comment that relate to our models.

Editing our Post model

We need to update our Post model to add the has_many relationship to the Comment model. In the app/models/post.rb file, add the following:

class Post < ApplicationRecord has_many :comments, dependent: :destroy end

This lets the model know that we have a one-to-many relationship with the Comment model.

Exploring the generated GraphQL files

Within the app/graphql folder, there will be the base files that we scaffolded out.

The app/graphql/demo_graphql_server_schema.rb adds in our query and mutation type and sets up the schema, while the Post and Comment objects we created can be found under app/graphql/types as the post_type.rb and comment.rb files.

I've updated those files to look like the following.

For app/graphql/types/post_type.rb:

# frozen_string_literal: true module Types class PostType < Types::BaseObject description 'A blog post' field :id, ID, null: false field :title, String, null: false field :rating, Integer, null: false field :comments, [Types::CommentType] end end

For app/graphql/types/comment_type.rb:

# frozen_string_literal: true module Types class CommentType < Types::BaseObject field :id, ID, null: false field :body, String, null: false field :post, Types::PostType, null: false end end

To enable the resolvers for these queries, we can update our file app/graphql/types/query_type.rb:

module Types class QueryType < Types::BaseObject # Add `node(id: ID!) and `nodes(ids: [ID!]!)` include GraphQL::Types::Relay::HasNodeField include GraphQL::Types::Relay::HasNodesField # Add root-level fields here. # They will be entry points for queries on your schema. field :posts, [Types::PostType], null: false, description: 'Returns a list of all posts' def posts Post.all end field :comments, [Types::CommentType], null: false def comments Comment.all end end end

The above code will help our queries resolve for the Post and Comment objects. The def posts and def comments methods will return all of the posts and comments as our contrived behavior. In practice, you will want to add pagination and filtering.

Creating our seeds

At this point, we are ready to add some seeds to see our GraphiQL interface in action. Add the following to db/seeds.rb:

# This file should contain all the record creation needed to seed the database with its default values. # The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup). # # Examples: # # movies = Movie.create([{ name: "Star Wars" }, { name: "Lord of the Rings" }]) # Character.create(name: "Luke", movie: movies.first) # db/seeds.rb post = Post.create!( title: 'My first post', rating: 4 ) post_two = Post.create!( title: 'A second, less impressive post', rating: 2 ) Comment.create!( [ { body: 'Loved it', post: post }, { body: 'Gr8 m8', post: post }, { body: 'Worst one yet', post: post_two }, { body: 'I want my money back', post: post_two }, { body: 'You could do better', post: post_two } ] )

Here we are creating two different posts, then attaching comments to each of them (two for the first and three for the second respectively).

At this point, we are now ready to run some database migrations and start the server.

Running migrations and starting the server

# Run migrations and seeding $ bin/rails db:create db:migrate db:seed # Start the server on port 3000 $ bin/rails s

The above does the following:

  1. Run the migrations and seed the database with db:create, db:migrate and db:seed.
  2. Start the server on port 3000 with bin/rails s.

At this point, we can navigate to http://localhost:3000/graphiql to see our GraphiQL interface and start playing around.

A query to get our posts and comments

I won't go into detail on how the GraphiQL interface works. If you are not familiar, you can check out the Gatsby intro on GraphiQL.

For us, we are going to write in our two queries to see what we get back.

Our first query will be PostsWithComments:

query PostsWithComments { posts { id title rating comments { id body } } }

If we run this query, we will get back a list of posts and their comments.

{ "data": { "posts": [ { "id": "1", "title": "My first post", "rating": 4, "comments": [ { "id": "1", "body": "Loved it" }, { "id": "2", "body": "Gr8 m8" } ] }, { "id": "2", "title": "A second, less impressive post", "rating": 2, "comments": [ { "id": "3", "body": "Worst one yet" }, { "id": "4", "body": "I want my money back" }, { "id": "5", "body": "You could do better" } ] } ] } }

Result for our query PostsWithComments

Result for our query PostsWithComments

Amazing! With a simple query, we are able to get back all the posts with their related comments.

A query mapping the comments to the posts

GraphQL is all about flexible relationships. A cool demonstration on the power of this is to go the other way and request comments as the primary source of data and attach the related post when required:

query CommentsWithPosts { comments { id body post { id title rating } } }

If we run our new CommentsWithPosts query, we will get back a list of comments and their related posts.

{ "data": { "comments": [ { "id": "1", "body": "Loved it", "post": { "id": "1", "title": "My first post", "rating": 4 } }, { "id": "2", "body": "Gr8 m8", "post": { "id": "1", "title": "My first post", "rating": 4 } }, { "id": "3", "body": "Worst one yet", "post": { "id": "2", "title": "A second, less impressive post", "rating": 2 } }, { "id": "4", "body": "I want my money back", "post": { "id": "2", "title": "A second, less impressive post", "rating": 2 } }, { "id": "5", "body": "You could do better", "post": { "id": "2", "title": "A second, less impressive post", "rating": 2 } } ] } }

Result for our query PostsWithComments

Result for our query PostsWithComments

Summary

Today's post demonstrated how to ...

Resources and further reading

Photo credit: unstable_affliction

Personal image

Dennis O'Keeffe

@dennisokeeffe92
  • Melbourne, Australia

Hi, I am a professional Software Engineer. Formerly of Culture Amp, UsabilityHub, Present Company and NightGuru.
I am currently working on workingoutloud.dev, Den Dribbles and LandPad .

1,200+ PEOPLE ALREADY JOINED ❤️️

Get fresh posts + news direct to your inbox.

No spam. We only send you relevant content.