# Setting Up GraphQL and GraphiQL in Rails: A Comprehensive Guide

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`:

```ruby
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:

```bash
bundle install
rails generate graphql:install
```

This will create the basic GraphQL structure in your Rails application:

```ruby
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:

```ruby
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:

```ruby
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:

1. Extract the authentication token from the request headers
    
2. Find the corresponding user
    
3. Make the user available throughout your GraphQL resolvers via context
    

You can then access the current user in any resolver or mutation:

```ruby
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`:

```ruby
GraphiQL::Rails.config.header_editor_enabled = true
GraphiQL::Rails.config.title = 'Your API Name'
```

Update your `config/application.rb` to handle cookies for GraphiQL:

```ruby
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`:

```ruby
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`:

```ruby
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:

```ruby
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:

```ruby
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:

```ruby
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:

```graphql
query {
  __schema {
    types {
      name
    }
  }
}
```

![GraphiQL View in Rails](https://cdn.hashnode.com/res/hashnode/image/upload/v1733472993687/79f325c0-10ce-4e0b-9745-2939146f13a1.png align="center")

## Security Considerations

1. Limit GraphiQL to non-production environments
    
2. Implement proper authentication
    
3. Use query depth limiting to prevent complex nested queries
    
4. 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!
