Rails GraphQL API in 2026: graphql-ruby, Subscriptions en Sollicitatievragen
Een productieklare GraphQL API bouwen met Rails 8 en graphql-ruby. Schema-ontwerp, mutations, subscriptions met ActionCable en voorbereiding op sollicitatiegesprekken.

GraphQL is de standaardkeuze geworden voor API's die flexibele data-ophaling nodig hebben, en graphql-ruby brengt deze functionaliteit naar Rails met nauwe ActiveRecord-integratie. Rails 8, uitgebracht eind 2024, werkt uitstekend samen met graphql-ruby 2.4, dat verbeterde subscription-afhandeling en betere lazy execution voor N+1-preventie introduceerde.
De graphql-ruby gem biedt een complete GraphQL-implementatie: schema-definitie met een Ruby DSL, automatische type-inferentie uit ActiveRecord-modellen, ingebouwde DataLoader voor batching en ActionCable-integratie voor realtime subscriptions.
graphql-ruby Instellen in een Rails 8 Applicatie
De gem-generator maakt de initiële schemastructuur aan en koppelt het GraphQL-endpoint. Begin met het toevoegen van de gem en voer de install-generator uit om de basisbestanden te creëren.
# Gemfile
gem 'graphql', '~> 2.4'# Terminal
bundle install
rails generate graphql:installDe generator maakt app/graphql/ aan met het schemabestand, basistypes en een mutations-directory. Het voegt ook een route toe op /graphql en koppelt optioneel GraphiQL voor ontwikkeling.
# app/graphql/sharpskill_schema.rb
class SharpskillSchema < GraphQL::Schema
mutation(Types::MutationType)
query(Types::QueryType)
subscription(Types::SubscriptionType)
# Use the built-in DataLoader for N+1 prevention
use GraphQL::Dataloader
# Required for subscriptions
use GraphQL::Subscriptions::ActionCableSubscriptions
endHet schemabestand fungeert als toegangspunt. Het declareert welke types queries, mutations en subscriptions afhandelen, en registreert middleware zoals DataLoader.
Types en Resolvers Definiëren voor Rails-Modellen
Elk ActiveRecord-model dat in de API verschijnt, heeft een corresponderend GraphQL-type nodig. Het type definieert welke velden worden blootgesteld en hoe ze worden opgelost.
# app/graphql/types/user_type.rb
module Types
class UserType < Types::BaseObject
field :id, ID, null: false
field :email, String, null: false
field :created_at, GraphQL::Types::ISO8601DateTime, null: false
# Association with automatic batching via DataLoader
field :posts, [Types::PostType], null: false
def posts
dataloader.with(Sources::ActiveRecordCollection, Post, :user_id).load(object.id)
end
end
endDe dataloader.with-aanroep bundelt meerdere posts-ophalingen in één SQL-query. Zonder DataLoader zou een query die 50 gebruikers met hun posts opvraagt 51 queries uitvoeren. Met DataLoader zijn het er 2.
# app/graphql/sources/active_record_collection.rb
class Sources::ActiveRecordCollection < GraphQL::Dataloader::Source
def initialize(model, foreign_key)
@model = model
@foreign_key = foreign_key
end
def fetch(ids)
records = @model.where(@foreign_key => ids).group_by(&@foreign_key)
ids.map { |id| records[id] || [] }
end
endDit patroon verschijnt in elk serieus graphql-ruby-project. De officiële DataLoader-documentatie behandelt aanvullende use cases zoals caching en geneste sources.
Queries Bouwen met Argumenten en Filtering
Het QueryType definieert de root-velden die beschikbaar zijn voor clients. Argumenten maken filtering en paginering mogelijk.
# app/graphql/types/query_type.rb
module Types
class QueryType < Types::BaseObject
field :users, [Types::UserType], null: false do
argument :email_contains, String, required: false
argument :limit, Integer, required: false, default_value: 20
end
def users(email_contains: nil, limit:)
scope = User.all
scope = scope.where('email ILIKE ?', "%#{email_contains}%") if email_contains
scope.limit(limit)
end
field :user, Types::UserType, null: true do
argument :id, ID, required: true
end
def user(id:)
User.find_by(id: id)
end
end
endResolver-methoden ontvangen keyword-argumenten die overeenkomen met de velddefinitie. Het retourneren van nil uit een nullable veld is geldig; het gooien van een error uit een non-null veld triggert een GraphQL-foutrespons.
Klaar om je Ruby on Rails gesprekken te halen?
Oefen met onze interactieve simulatoren, flashcards en technische tests.
Mutations: Records Aanmaken en Bijwerken
Mutations volgen een striktere conventie dan queries. Elke mutation leeft in zijn eigen klasse en retourneert een payload-type dat zowel het resultaat als eventuele fouten bevat.
# app/graphql/mutations/create_post.rb
module Mutations
class CreatePost < Mutations::BaseMutation
argument :title, String, required: true
argument :body, String, required: true
field :post, Types::PostType, null: true
field :errors, [String], null: false
def resolve(title:, body:)
post = context[:current_user].posts.build(title: title, body: body)
if post.save
{ post: post, errors: [] }
else
{ post: nil, errors: post.errors.full_messages }
end
end
end
endDe context[:current_user] komt uit de controller. Authenticatie gebeurt vóór de GraphQL-laag, meestal met Devise of een JWT-bibliotheek.
# app/controllers/graphql_controller.rb
class GraphqlController < ApplicationController
def execute
context = {
current_user: current_user,
request: request
}
result = SharpskillSchema.execute(
params[:query],
variables: params[:variables],
context: context,
operation_name: params[:operationName]
)
render json: result
end
endToegangsbeheer binnen resolvers controleert context[:current_user] en gooit GraphQL::ExecutionError wanneer niet geautoriseerd. De graphql-ruby autorisatiegids beschrijft veld-niveau en type-niveau autorisatiepatronen in detail.
Realtime Updates met GraphQL Subscriptions en ActionCable
Subscriptions stellen clients in staat om updates te ontvangen wanneer server-side events plaatsvinden. Rails ActionCable handelt de WebSocket-verbinding af, en graphql-ruby integreert via GraphQL::Subscriptions::ActionCableSubscriptions.
# app/graphql/types/subscription_type.rb
module Types
class SubscriptionType < Types::BaseObject
field :post_created, Types::PostType, null: false do
argument :user_id, ID, required: false
end
def post_created(user_id: nil)
object # The object passed from trigger
end
end
endHet triggeren van een subscription gebeurt vanuit elke plek in de applicatie, meestal in een model-callback of service-object.
# app/models/post.rb
class Post < ApplicationRecord
belongs_to :user
after_create_commit :notify_subscribers
private
def notify_subscribers
SharpskillSchema.subscriptions.trigger(
:post_created,
{ user_id: user_id },
self
)
end
endHet ActionCable-channel dat GraphQL-subscriptions afhandelt wordt met de gem meegeleverd.
# app/channels/graphql_channel.rb
class GraphqlChannel < ApplicationCable::Channel
def subscribed
@subscription_ids = []
end
def execute(data)
result = SharpskillSchema.execute(
data['query'],
variables: data['variables'],
context: { current_user: current_user, channel: self },
operation_name: data['operationName']
)
payload = { result: result.to_h, more: result.subscription? }
@subscription_ids << result.context[:subscription_id] if result.subscription?
transmit(payload)
end
def unsubscribed
@subscription_ids.each do |sid|
SharpskillSchema.subscriptions.delete_subscription(sid)
end
end
endAan de client-kant verbinden bibliotheken zoals Apollo Client of urql met de ActionCable WebSocket en beheren de subscription-status. Voor sollicitatievoorbereidng over ActionCable-mechanismen, zie de ActionCable & WebSockets module.
GraphQL API's Testen met RSpec
Het testen van een GraphQL API vereist het uitvoeren van queries tegen het schema en het verifiëren van de responsstructuur en data.
# spec/graphql/queries/users_spec.rb
RSpec.describe 'Users query' do
let!(:user) { create(:user, email: 'test@example.com') }
let(:query) do
<<~GRAPHQL
query {
users(emailContains: "test") {
id
email
}
}
GRAPHQL
end
it 'returns users matching the filter' do
result = SharpskillSchema.execute(query)
users = result.dig('data', 'users')
expect(users.length).to eq(1)
expect(users.first['email']).to eq('test@example.com')
end
endMutation-tests verifiëren zowel succes- als validatiefout-paden.
# spec/graphql/mutations/create_post_spec.rb
RSpec.describe Mutations::CreatePost do
let(:user) { create(:user) }
let(:context) { { current_user: user } }
let(:mutation) do
<<~GRAPHQL
mutation($title: String!, $body: String!) {
createPost(input: { title: $title, body: $body }) {
post { id title }
errors
}
}
GRAPHQL
end
it 'creates a post when valid' do
result = SharpskillSchema.execute(
mutation,
variables: { title: 'Hello', body: 'World' },
context: context
)
data = result.dig('data', 'createPost')
expect(data['errors']).to be_empty
expect(data['post']['title']).to eq('Hello')
end
it 'returns errors when invalid' do
result = SharpskillSchema.execute(
mutation,
variables: { title: '', body: 'World' },
context: context
)
data = result.dig('data', 'createPost')
expect(data['errors']).to include("Title can't be blank")
end
endVoor meer Rails-testpatronen, zie de Testing with RSpec module.
Veelvoorkomende GraphQL Sollicitatievragen voor Rails-Ontwikkelaars
Interviewers die GraphQL-kennis testen in een Rails-context richten zich vaak op praktische implementatiezaken in plaats van abstracte type-theorie.
Hoe voorkom je N+1-queries in graphql-ruby?
Met DataLoader en custom sources. Definieer een source-klasse die database-aanroepen bundelt, en roep dataloader.with(SourceClass, args).load(id) aan in resolvers. DataLoader verzamelt alle ID's die in een enkele GraphQL-uitvoering worden opgevraagd en haalt ze op in één query.
Wat is het verschil tussen een query en een mutation?
Semantiek: queries lezen data en mogen geen bijeffecten hebben. Mutations wijzigen data en kunnen bijeffecten hebben. GraphQL garandeert parallelle uitvoering voor query-velden en sequentiële uitvoering voor mutation-velden, dus twee mutations in hetzelfde verzoek worden op volgorde uitgevoerd.
Hoe werken subscriptions in Rails?
Subscriptions gebruiken ActionCable voor WebSocket-verbindingen. De client stuurt een subscription-query via het WebSocket. De server slaat de subscription op en pusht bij aanroep van trigger het resultaat naar alle overeenkomende clients. De subscription-ID stelt clients in staat om zich af te melden.
Wanneer zou je GraphQL boven REST kiezen voor een Rails API?
GraphQL vermindert over-fetching wanneer clients verschillende subsets van data nodig hebben, wat gebruikelijk is bij mobiele apps met variërende schermgroottes. Het elimineert ook de noodzaak voor meerdere REST-endpoints wanneer een enkele view data van meerdere modellen vereist. REST blijft eenvoudiger voor CRUD-zware API's met consistente datastructuren en voor publieke API's waar caching kritiek is.
Hoe ga je om met authenticatie en autorisatie in graphql-ruby?
Authenticatie gebeurt in de controller vóór GraphQL-uitvoering, meestal via Devise, Warden of JWT-verificatie. De geauthenticeerde gebruiker wordt doorgegeven in context. Autorisatie gebeurt in resolvers of via de authorized?-hook van graphql-ruby op types en mutations, waarbij GraphQL::ExecutionError wordt gegooid wanneer toegang wordt geweigerd.
Voor meer Ruby on Rails sollicitatievoorbereiding, zie de Rails API Mode module, die REST API-ontwerppatronen behandelt die GraphQL-kennis aanvullen.
Begin met oefenen!
Test je kennis met onze gespreksimulatoren en technische tests.
Productie GraphQL API's Bouwen met Rails: Kernpunten
- Installeer graphql-ruby met
rails generate graphql:installom schema, types en routing te scaffolden - Gebruik DataLoader sources voor alle associaties om database-queries te bundelen en N+1-performanceproblemen te voorkomen
- Definieer mutations in aparte klassen met expliciete foutvelden in het returntype
- Integreer subscriptions via ActionCable voor realtime updates, getriggerd vanuit model-callbacks of service-objecten
- Test queries en mutations door ze direct tegen het schema uit te voeren in RSpec
- Authenticatie hoort in de controller; autorisatiecontroles gebeuren binnen resolvers met
context[:current_user] - Kies GraphQL wanneer clients flexibele data-ophaling nodig hebben; blijf bij REST voor simpele CRUD API's met uniforme responses
Zie jij de bug in Ruby on Rails?
Een echt codefragment, een verborgen bug, één poging per dag. Zonder account uit te proberen.

Geschreven door
Anthony Fillion-MailletOprichter van SharpSkill
Al meer dan 10 jaar fullstack-ontwikkelaar. Hij leidt SharpSkill en staat in voor alles wat hier verschijnt.
Bijgewerkt op 19 september 2026
Delen
Gerelateerde artikelen

Rails Background Jobs in 2026: Sidekiq vs Good Job Vergelijking met Sollicitatievragen
Uitgebreide vergelijking van Sidekiq, Good Job en Solid Queue voor Rails background jobs. Handleiding voor het kiezen van de juiste oplossing met typische technische sollicitatievragen.

Rails Active Storage in 2026: Bestandsuploads, S3-Integratie en Sollicitatievragen
Beheers Rails Active Storage voor bestandsuploads met S3 en directe uploads. Complete tutorial met codevoorbeelden en veelgestelde sollicitatievragen over bestandsafhandeling in Ruby on Rails.

Rails Stimulus en Importmaps in 2026: Modern JavaScript Zonder Build Tools
Ontdek hoe Rails Stimulus en Importmaps JavaScript-ontwikkeling mogelijk maken zonder webpack of esbuild. Complete tutorial met controllers, Outlets API en debugging-technieken.