Table of Contents
- Initial Configuration
- Generate a New Rails API
- Gem Additions
rack-cors
Gem Configuration- First Migration
- New Graphql Generator
- Schema, Types
- Resources
In this blog, I'll be covering how to create an initial Rails backend API utilizing Graphql. If you don't know Graphql, if you're familiar with it or just need a refresher, this blog is for you.
Initial Configuration
Generate a New Rails API
Let's generate a new API-only application. I won't be using most of the gems that come with a new rails generation, so the command I will use with numerous options is:
rails new vacationme_backend --api --database=postgresql --skip-action-mailer --skip-action-mailbox --skip-action-cable
Gem Additions
- Uncomment the
rack-cors
gem - Add
gem 'graphql'
- Add
gem 'graphiql-rails'
- Run
bundle install
Unfortunately, the graphiql-rails
hasn't been updated since January of 2019. There are many pull requests and issues stated, and quite a few direct you to how the application can begin working again. I will show you how you can do so further down.
rack-cors
Configuration
In config/initializers/cors.rb
, uncomment the following code:
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*', headers: :any, methods: [:get, :post, :patch, :put]
end
end
For Rails, you'll need to add this middleware on application startup. A practical way to do this is with an initializer file. For example, the following will allow GET, POST, PATCH, or PUT requests from any origin on any resource:
We use
insert_before
to make sureRack::Cors
runs at the beginning of the stack to make sure it isn't interfered with by other middleware (seeRack::Cache
note in Common Gotchas section). Basic setup examples for Rails 5 & Rails 6 can be found in the examples/ directory.
In config/application.rb
, add:
config.hosts << "localhost"
Rails 6 has support for blocking requests from unknown hosts, so origin domains will need to be added there as well.
A more detailed reason for this addition can be found here in the Ruby on Rails Guide.
First Migration
Graphql will be interacting with ActiveRecord. We will have to create our migrations and models as we normally would. I am using the bcrypt
gem, so instead of a password
field, it will be a password_digest
field.
Run:
rails g model user name:string username:string password_digest:string
rails db:create
rails db:migrate
Remember to include has_secure_password
in app/models/user.rb
. Now let's write two seeds in db/seeds.rb
:
User.create(
name: "John Doe",
username: "JohnDoe",
password: "123"
)
User.create(
name: "Ethan Gustafson",
username: "GoodGuyGuf",
password: "123"
)
- Run
rails db:seed
Mounting The Engine
The graphiql-rails
gem enables one route in your application where you can open a browser and develop using an IDE for graphql.
After navigating through the issues, I stumbled onto the best solution I could use without changing much of the code I currently have. It can be found here in this issue.
Follow the graphiql-rails
guide normally.
# config/routes.rb
post "/graphql", to: "graphql#execute"
if Rails.env.development?
mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "graphql#execute"
end
You would navigate to "/graphiql" in your browser, and the path would still use the graphql#execute
action.
In config/application.rb
, uncomment:
require "sprockets/railtie"
Sprockets is a Ruby library for compiling and serving web assets.
To create the last fix, run touch app/assets/config/manifest.js
to create a manifest.js file. Put this inside of it:
//= link graphiql/rails/application.css
//= link graphiql/rails/application.js
That's all. This is so the gem can link to the CSS and js it defined in its own files. Now we can begin building the types.
New Graphql Generator
Now that we have a user and a record, we can generate the graphql
install. Run:
rails generate graphql:install
This will create:
- A
graphql_controller
- A
graphql
directory containing two subdirectories and one file:-
mutations
, which contains 1 file -
types
, which contains 10 files project_name_schema.rb
-
To keep it simple I won't go into detail about the mutations directory.
Schema, Types
GraphQL cannot execute a query without a type system.
There are object, mutation, query, scalar, enumeration, interfaces, union, and input types.
Every GraphQL service defines a set of types which completely describe the set of possible data you can query on that service. Then, when queries come in, they are validated and executed against that schema.
Before building a schema, you have to define an entry point to your system, which is called the “query root”. The query root will be the
query_type.rb
file.
# 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.
# First describe the field signature:
field :user, UserType, null: true do
description "Find a User by ID"
argument :id, ID, required: true
end
def user(id:)
User.find(id)
end
end
end
The User
Type:
module Types
class UserType < Types::BaseObject
field :id, ID, null: false
field :name, String, null: false
field :username, String, null: false
field :password, String, null: false
end
end
Including the root query in the schema ensures that the application is now functional. Run rails s
. Your application should be working normally, and you can run queries on the types above without a problem.
# app/graphql/vacationme_backend_schema.rb
class VacationmeBackendSchema < GraphQL::Schema
mutation(Types::MutationType)
query(Types::QueryType)
# Opt in to the new runtime (default in future graphql-ruby versions)
use GraphQL::Execution::Interpreter
use GraphQL::Analysis::AST
# Add built-in connections for pagination
use GraphQL::Pagination::Connections
end
Results:
Top comments (0)