Agent skill

rails-graphql-patterns

Analyzes and recommends GraphQL patterns for Rails using graphql-ruby including schema design, types, resolvers, mutations, subscriptions, DataLoader, and query complexity. Use when building GraphQL APIs, defining types, writing mutations, optimizing N+1 queries, or structuring app/graphql. NOT for REST API controllers, ActiveRecord queries outside GraphQL, or Turbo Stream responses.

Stars 4
Forks 0

Install this agent skill to your Project

npx add-skill https://github.com/ag0os/rails-dev-plugin/tree/main/skills/rails-graphql-patterns

SKILL.md

Rails GraphQL Patterns

Analyze and recommend patterns for building GraphQL APIs in Rails with graphql-ruby.

Follow standard graphql-ruby conventions for type definitions, input types, enum types, query types, and basic mutations. This skill focuses on non-obvious patterns and opinionated decisions.

Core Principles

  1. Batch loading: Always use DataLoader to prevent N+1 queries — never resolve associations directly
  2. Structured errors: Return error arrays in mutation payloads, not exceptions
  3. Field-level authorization: Check permissions per field, not just per query
  4. Complexity limits: Set max_complexity and max_depth on the schema
  5. Null annotations: Be intentional with null: true/false on every field

DataLoader for N+1 Prevention

Every association field MUST use DataLoader. Never call object.association directly in a resolver.

ruby
class Sources::RecordLoader < GraphQL::Dataloader::Source
  def initialize(model_class, column: :id)
    @model_class = model_class
    @column = column
  end

  def fetch(ids)
    records = @model_class.where(@column => ids).index_by { |r| r.send(@column) }
    ids.map { |id| records[id] }
  end
end

# Usage in type
def author
  dataloader.with(Sources::RecordLoader, User).load(object.user_id)
end

See patterns.md for AssociationLoader and CountLoader variants.

Connection Types (Pagination)

Always use connection types for list fields — never return unbounded arrays.

ruby
module Types
  class PostConnectionType < GraphQL::Types::Connection
    edge_type(Types::PostEdgeType)
    field :total_count, Integer, null: false

    def total_count
      object.items.size
    end
  end
end

# In query type
field :posts, Types::PostConnectionType, null: false, connection: true do
  argument :filter, Types::PostFilterInput, required: false
end

Subscriptions — Triggering from Models

ruby
# Trigger from model after_create_commit, not from mutations
class Post < ApplicationRecord
  after_create_commit :notify_subscribers

  private

  def notify_subscribers
    MyAppSchema.subscriptions.trigger(:post_created, {}, self)
  end
end

Schema Configuration

ruby
class MyAppSchema < GraphQL::Schema
  max_complexity 300
  max_depth 15
  default_max_page_size 25

  use GraphQL::Dataloader

  rescue_from ActiveRecord::RecordNotFound do |_err, _obj, _args, _ctx, field|
    raise GraphQL::ExecutionError, "#{field.type.unwrap.graphql_name} not found"
  end
end

Per-field complexity for expensive operations:

ruby
field :expensive_field, String do
  complexity 50
end

Anti-Patterns

Anti-Pattern Fix
N+1 in resolvers Use DataLoader / Sources
No complexity limits Set max_complexity and max_depth
Raising exceptions in mutations Return { errors: [...] } in payload
Authorization only at query root Check auth at field level
Exposing ActiveRecord directly Define explicit GraphQL types
Fat resolvers with business logic Delegate to service objects
No pagination on list fields Use connection types

Output Format

When analyzing or creating GraphQL components, provide:

  1. Type/mutation file with proper null annotations
  2. DataLoader source if associations are resolved
  3. Schema configuration (complexity, depth, pagination)
  4. Test outline executing queries against the schema
  5. Authorization strategy (context, field-level checks)

Error Handling

  • Mutations return { resource: nil, errors: [...] } on validation failure
  • Use rescue_from in schema for RecordNotFound mapped to GraphQL::ExecutionError
  • Field-level: return nil or raise GraphQL::ExecutionError for unauthorized access
  • Never expose internal error details to clients in production

Expand your agent's capabilities with these related and highly-rated skills.

ag0os/rails-dev-plugin

rails-caching-patterns

Caching patterns for Rails applications including fragment caching, low-level caching, HTTP caching, Russian doll caching, and cache invalidation strategies. Automatically invoked when working with Rails.cache, cache stores, stale?/fresh_when, fragment caching, cache keys, or performance optimization through caching. Triggers on "cache", "caching", "Rails.cache", "fragment cache", "Russian doll", "stale?", "fresh_when", "cache key", "cache store", "Redis cache", "Solid Cache", "memcached", "ETag", "cache invalidation", "cache bust". NOT for CDN configuration (use rails-devops-patterns) or database query optimization (use rails-model-patterns).

4 0
Explore
ag0os/rails-dev-plugin

ruby-object-design

Automatically invoked when making decisions about Ruby code structure and organization. Triggers on "class or module", "should this be a class", "struct vs class", "PORO", "data object", "design pattern", "class vs module", "when to use class", "module vs class", "stateless class", "value object", "data container", "object factory", "extend self", "singleton class". Provides guidance on choosing the right Ruby construct (class, module, Struct, Data, Hash). NOT for code smell identification or refactoring (use ruby-refactoring) or Rails-specific framework patterns.

4 0
Explore
ag0os/rails-dev-plugin

rails-views-patterns

Analyzes Rails view templates, partials, layouts, helpers, and form patterns for best practices. Use when reviewing ERB templates, improving view performance with fragment caching, fixing form helpers, organizing partials, adding accessibility attributes, or evaluating collection rendering. NOT for Stimulus/Turbo logic (use hotwire-patterns), controller concerns, or API-only responses.

4 0
Explore
ag0os/rails-dev-plugin

rails-architecture-patterns

Provides architectural planning, design decisions, and coordination guidance for Rails applications. Use when planning new features, choosing between design approaches (STI vs polymorphic, service vs concern, monolith vs engine), evaluating system architecture, or deciding which domain skill or agent to delegate to. NOT for implementation details within a single domain (use the domain-specific skill instead).

4 0
Explore
ag0os/rails-dev-plugin

rails-mailer-patterns

Action Mailer patterns for Rails applications. Automatically invoked when working with email delivery, mailer classes, email templates, mailer previews, interceptors, or delivery configuration. Triggers on "mailer", "email", "ActionMailer", "deliver_later", "deliver_now", "mail template", "email preview", "SMTP", "SendGrid", "Postmark", "notification email". NOT for push notifications, SMS, or in-app messaging.

4 0
Explore
ag0os/rails-dev-plugin

rails-devops-patterns

Analyzes Rails deployment, infrastructure, and production configuration for best practices. Use when setting up Docker, writing CI/CD pipelines, configuring Puma, adding monitoring or logging, hardening security (SSL, Rack::Attack, headers), optimizing database config, or reviewing production environment files. NOT for application business logic, model design, or test writing.

4 0
Explore

Didn't find tool you were looking for?

Be as detailed as possible for better results