GraphQL is becoming increasingly popular as an alternative to REST APIs, offering more flexibility and efficiency in data fetching. In this guide, we'll walk through setting up GraphQL and GraphiQL in a Rails application, using practical examples from a real-world implementation.
Prerequisites
Ruby on Rails 7.2+
Ruby 3.3+
Basic understanding of Rails applications
Step 1: Adding Required Gems
First, add the necessary gems to your Gemfile
:
gem 'graphql', '2.3.14'
gem 'graphiql-rails', '1.10.1'
Step 2: Installing GraphQL
Run the following commands to install GraphQL and generate the base files:
bundle install
rails generate graphql:install
This will create the basic GraphQL structure in your Rails application:
app/
└── graphql/
├── types/
│ ├── base_object.rb
│ ├── base_enum.rb
│ ├── base_input_object.rb
│ ├── base_interface.rb
│ ├── base_scalar.rb
│ ├── base_union.rb
│ ├── query_type.rb
│ └── mutation_type.rb
├── mutations/
│ └── base_mutation.rb
└── [your_app]_schema.rb
Step 3: Setting Up GraphQL Controller
Create a GraphQL controller to handle requests:
class GraphqlController < ApplicationController
def execute
variables = prepare_variables(params[:variables])
query = params[:query]
operation_name = params[:operationName]
context = {
current_user: current_user # This comes from ApplicationController
}
result = YourAppSchema.execute(query,
variables: variables,
context: context,
operation_name: operation_name)
render json: result
rescue StandardError => e
raise e unless Rails.env.development?
handle_error_in_development(e)
end
private
# ... [rest of the controller code]
end
Authentication Setup
The current_user
method is defined in your ApplicationController
. Here's how to set it up:
class ApplicationController < ActionController::API
def auth_header
request.headers['Authorization']&.split&.last
end
def current_user
Current.user = User.find_by_token_for(:auth_token, auth_header)
@current_user ||= Current.user
end
end
This setup allows you to:
Extract the authentication token from the request headers
Find the corresponding user
Make the user available throughout your GraphQL resolvers via context
You can then access the current user in any resolver or mutation:
module Mutations
class BaseMutation < GraphQL::Schema::RelayClassicMutation
def current_user
context[:current_user]
end
def authenticate_user!
raise GraphQL::ExecutionError, 'Not authenticated' unless current_user
end
end
end
Step 4: Configuring GraphiQL
Add GraphiQL configuration in config/initializers/graphiql.rb
:
GraphiQL::Rails.config.header_editor_enabled = true
GraphiQL::Rails.config.title = 'Your API Name'
Update your config/application.rb
to handle cookies for GraphiQL:
config.middleware.use ActionDispatch::Cookies
config.middleware.use ActionDispatch::Session::CookieStore
config.middleware.insert_after(ActionDispatch::Cookies, ActionDispatch::Session::CookieStore)
Step 5: Setting Up Routes
Add GraphQL routes to config/routes.rb
:
Rails.application.routes.draw do
post "/graphql", to: "graphql#execute"
if !Rails.env.production?
mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/graphql"
end
end
Step 6: CORS Configuration
If you're building an API, configure CORS in config/initializers/cors.rb
:
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins "*"
resource "*",
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
Best Practices
1. Structured Type Definitions
Organize your types in a modular way:
module Types
class BaseObject < GraphQL::Schema::Object
edge_type_class(Types::BaseEdge)
connection_type_class(Types::BaseConnection)
field_class Types::BaseField
end
end
2. Implement Base Mutations
Create a base mutation class for common functionality:
module Mutations
class BaseMutation < GraphQL::Schema::RelayClassicMutation
argument_class Types::BaseArgument
field_class Types::BaseField
input_object_class Types::BaseInputObject
object_class Types::BaseObject
end
end
3. Error Handling
Implement consistent error handling across your GraphQL API:
module Mutations
class BaseMutationWithErrors < BaseMutation
field :errors, [String], null: true
field :success, Boolean, null: false
def handle_errors(record)
{
success: false,
errors: record.errors.full_messages
}
end
end
end
Testing Your Setup
After completing the setup, you can access GraphiQL at http://localhost:3000/graphiql
in development. Try this query:
query {
__schema {
types {
name
}
}
}
Security Considerations
Limit GraphiQL to non-production environments
Implement proper authentication
Use query depth limiting to prevent complex nested queries
Consider implementing rate limiting
Conclusion
With this setup, you have a solid foundation for building a GraphQL API in Rails. The included GraphiQL interface provides a powerful tool for testing and documenting your API during development.
Remember to:
Keep your schema well-organized
Implement proper error handling
Follow security best practices
Write comprehensive tests for your GraphQL endpoints
This setup provides a robust starting point for building scalable GraphQL APIs with Rails.
Happy Coding!
Top comments (0)