Before we get started the tools we'll use to build our API.
Ruby 3.1 or greater
Rails 7 or greater
PostgreSQL
The graphql-ruby gem. (Documentation)
Creating The Rails API
rails new PROJECT_NAME --api --database=postgresql
rails db:create
rails db:migrate
Installing the gems we need
gem 'rack-cors'
gem 'graphql'
group :development do
gem 'graphiql-rails' # Adds graphiql so we can test queries
gem 'faker' # We'll use this to generate test data
end
Once these items are added to the .gemfile we need to install them by running the following in the terminal. After the gems have been installed, we need to run the generator to set up the graphql gem. This will create the base structure needed for our graphql api.
bundle install
rails generate graphql:install
After running the generator you should see a new folder in your app directory called "graphql". Additionally, the routes file(found at "config/routes.rb") should now contain a route for the graphql endpoint that will handle all of the queries and mutations we need for our blog. This is one of the biggest differences between a traditional rails api and one using graphql, in a traditional rails api we would need to create a route for each of our endpoints.
Rails.application.routes.draw do
post "/graphql", to: "graphql#execute"
end
We also need to go to "cors.rb" and uncomment the following code and update the "origins" to be localhost 3000. We'll run our rails api on port 3001.
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins "http://localhost:3000"
resource "*",
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
Next, let's set up graphiql so we can test our queries.
Rails.application.routes.draw do
if Rails.env.development?
mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "graphql#execute"
end
post "/graphql", to: "graphql#execute"
end
Before we are able to access graphiql there are a few more tweaks we need to make. First, we need to add the two lines with comments next to them to config/application.rb.
require_relative "boot"
require "rails/all"
require "sprockets/railtie" # add this line to enable sprockets. Required to use graphiql.
Bundler.require(*Rails.groups)
module RailsGql
class Application < Rails::Application
config.load_defaults 7.0
config.api_only = true
# add these lines to enable sessions. Required to use graphiql.
config.session_store :cookie_store, key: '_interslice_session'
config.middleware.use ActionDispatch::Cookies
config.middleware.use config.session_store, config.session_options
end
end
Next, we need to add an `assets` directory inside of `app`. After creating the `assets` directory, create another directory called `config` and add a file to that directory called `manifest.js`. Then include the following two lines, they appear to be commented out, but this is the syntax that sprockets expects.
//= link graphiql/rails/application.css
//= link graphiql/rails/application.js
That's all we need to get graphiql configured. We can test it out by running `rails s` to start the rails server, then navigating to `localhost:3000/graphiql`. The graphql gem adds a test query for us when running the generator, give it a test run to make sure it's working.
Next, let's add the model that we will need for the blog posts. This can be done manually but we'll use a rails generator to save some time. When creating a model, be sure to capitalize the name and use the singular form of the word (example: "User" not "Users"). Rails will handle pluralizing the names of the models if/when it's relevant.
rails g model Post title:string slug:string category:string body:text
And just like that, we've created a model and a database migration for our posts. To run the migration simply run 'rails db:migrate' again and it will create the table and its corresponding columns in the database. Now, let's use faker to add some fixture data for use to play with. To do this open the 'seeds.rb' file that is found in the 'db' folder and add the following.
5.times do
Post.create(title: Faker::Lorem.sentence(word_count: 3), slug: Faker::Internet.slug, body: Faker::Lorem::paragraph(sentence_count: 3))
end
Then run.
rails db:seed
rails g graphql:object post
Lastly, we need to add some queries to retrieve our post data. Update 'query_type.rb' to include the following fields and methods, we can remove the test field as well.
module Types
class QueryType < Types::BaseObject
# Add `node(id: ID!) and `nodes(ids: [ID!]!)`
include GraphQL::Types::Relay::HasNodeField
include GraphQL::Types::Relay::HasNodesField
field :posts, [Types::PostType], null: false
field :post, Types::PostType, null: false do
argument :id, ID, required: true
end
# Add root-level fields here.
# They will be entry points for queries on your schema.
def posts
Post.all
end
def post(id:)
Post.find(id)
end
end
end
Now we're ready to start setting up the front end!