2026'da Rails GraphQL API: graphql-ruby, Abonelikler ve Mülakat Soruları

Rails 8 ve graphql-ruby ile üretim düzeyinde GraphQL API oluşturma rehberi. Şema tasarımı, mutasyonlar, ActionCable ile abonelikler ve mülakat hazırlığı.

2026'da Rails GraphQL API: graphql-ruby, Abonelikler ve Mülakat Soruları

GraphQL, esnek veri çekme gerektiren API'ler için standart tercih haline geldi ve graphql-ruby, ActiveRecord ile sıkı entegrasyon sunarak bu yeteneği Rails'e taşıyor. 2024 sonunda yayınlanan Rails 8, geliştirilmiş abonelik desteği ve N+1 önleme için daha iyi tembel yürütme sunan graphql-ruby 2.4 ile mükemmel uyum sağlıyor.

graphql-ruby Rails'e ne kazandırır

graphql-ruby gem'i eksiksiz bir GraphQL implementasyonu sunar: Ruby DSL ile şema tanımı, ActiveRecord modellerinden otomatik tip çıkarımı, toplu işleme için yerleşik DataLoader ve gerçek zamanlı abonelikler için ActionCable entegrasyonu.

Rails 8 Uygulamasında graphql-ruby Kurulumu

Gem'in oluşturucusu başlangıç şema yapısını oluşturur ve GraphQL endpoint'ini bağlar. Gem'i ekleyip kurulum oluşturucusunu çalıştırarak temel dosyaları oluşturabilirsiniz.

ruby
# Gemfile
gem 'graphql', '~> 2.4'
bash
# Terminal
bundle install
rails generate graphql:install

Oluşturucu, şema dosyası, temel tipler ve mutasyonlar dizini ile app/graphql/ klasörünü oluşturur. Ayrıca /graphql altında bir route ekler ve isteğe bağlı olarak geliştirme için GraphiQL'i bağlar.

ruby
# app/graphql/sharpskill_schema.rb
class SharpskillSchema < GraphQL::Schema
  mutation(Types::MutationType)
  query(Types::QueryType)
  subscription(Types::SubscriptionType)

  # N+1 önleme için yerleşik DataLoader kullanımı
  use GraphQL::Dataloader

  # Abonelikler için gerekli
  use GraphQL::Subscriptions::ActionCableSubscriptions
end

Şema dosyası giriş noktası olarak görev yapar. Hangi tiplerin sorguları, mutasyonları ve abonelikleri işleyeceğini bildirir ve DataLoader gibi middleware'leri kaydeder.

Rails Modelleri için Tipler ve Çözücüler Tanımlama

API'de görünen her ActiveRecord modeli için karşılık gelen bir GraphQL tipi gerekir. Tip, hangi alanların açığa çıkarıldığını ve nasıl çözüldüğünü tanımlar.

ruby
# 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

    # DataLoader ile otomatik toplu işleme yapan ilişki
    field :posts, [Types::PostType], null: false

    def posts
      dataloader.with(Sources::ActiveRecordCollection, Post, :user_id).load(object.id)
    end
  end
end

dataloader.with çağrısı birden fazla post çekme işlemini tek bir SQL sorgusunda toplar. DataLoader olmadan, 50 kullanıcının postlarıyla birlikte istendiği bir sorgu 51 sorgu çalıştırır. DataLoader ile sadece 2 sorgu çalışır.

ruby
# 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
end

Bu kalıp ciddi her graphql-ruby projesinde görülür. Resmi DataLoader dokümantasyonu önbellekleme ve iç içe kaynaklar gibi ek kullanım durumlarını kapsar.

Argümanlar ve Filtreleme ile Sorgular Oluşturma

QueryType, istemcilere sunulan kök alanları tanımlar. Argümanlar filtreleme ve sayfalamayı mümkün kılar.

ruby
# 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
end

Çözücü metodları alan tanımına uyan anahtar kelime argümanları alır. Nullable bir alandan nil döndürmek geçerlidir; non-null bir alandan hata fırlatmak GraphQL hata yanıtını tetikler.

Ruby on Rails mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

Mutasyonlar: Kayıt Oluşturma ve Güncelleme

Mutasyonlar sorgulardan daha katı kurallara tabidir. Her mutasyon kendi sınıfında yaşar ve hem sonucu hem de olası hataları içeren bir payload tipi döndürür.

ruby
# 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
end

context[:current_user] controller'dan gelir. Kimlik doğrulama GraphQL katmanından önce, genellikle Devise veya bir JWT kütüphanesi kullanılarak gerçekleşir.

ruby
# 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
end

Çözücüler içindeki erişim kontrolü context[:current_user] değerini kontrol eder ve yetkilendirme olmadığında GraphQL::ExecutionError fırlatır. graphql-ruby yetkilendirme rehberi alan düzeyinde ve tip düzeyinde yetkilendirme kalıplarını detaylı açıklar.

GraphQL Abonelikleri ve ActionCable ile Gerçek Zamanlı Güncellemeler

Abonelikler, sunucu tarafı olayları gerçekleştiğinde istemcilerin güncellemeler almasını sağlar. Rails ActionCable WebSocket bağlantısını yönetir ve graphql-ruby GraphQL::Subscriptions::ActionCableSubscriptions aracılığıyla entegre olur.

ruby
# 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 # Trigger'dan geçirilen nesne
    end
  end
end

Aboneliği tetikleme uygulamanın herhangi bir yerinden yapılabilir, genellikle bir model callback'i veya servis nesnesinde.

ruby
# 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
end

GraphQL aboneliklerini yöneten ActionCable kanalı gem ile birlikte gelir.

ruby
# 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
end

İstemci tarafında Apollo Client veya urql gibi kütüphaneler ActionCable WebSocket'ine bağlanır ve abonelik durumunu yönetir. ActionCable mekanizmaları hakkında mülakat hazırlığı için ActionCable & WebSockets modülüne bakabilirsiniz.

RSpec ile GraphQL API Testi

GraphQL API testi, şemaya karşı sorgu çalıştırmayı ve yanıt yapısı ile verileri doğrulamayı gerektirir.

ruby
# 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
end

Mutasyon testleri hem başarı hem de doğrulama hatası yollarını doğrular.

ruby
# 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
end

Rails test kalıpları hakkında daha fazla bilgi için RSpec ile Test modülüne bakabilirsiniz.

Rails Geliştiricileri için Yaygın GraphQL Mülakat Soruları

Rails bağlamında GraphQL bilgisini test eden mülakatçılar, soyut tip teorisi yerine genellikle pratik uygulama konularına odaklanır.

graphql-ruby'de N+1 sorguları nasıl önlersiniz?

Özel kaynaklarla DataLoader kullanılır. Veritabanı çağrılarını toplu hale getiren bir kaynak sınıfı tanımlanır ve çözücülerde dataloader.with(SourceClass, args).load(id) çağrılır. DataLoader tek bir GraphQL yürütmesinde istenen tüm ID'leri toplar ve tek bir sorguda çeker.

Sorgu ile mutasyon arasındaki fark nedir?

Anlam açısından: sorgular veri okur ve yan etkileri olmamalıdır. Mutasyonlar veriyi değiştirir ve yan etkileri olabilir. GraphQL, sorgu alanları için paralel yürütme ve mutasyon alanları için sıralı yürütme garantisi verir, bu nedenle aynı istekteki iki mutasyon sırayla çalışır.

Rails'de abonelikler nasıl çalışır?

Abonelikler WebSocket bağlantıları için ActionCable kullanır. İstemci WebSocket üzerinden bir abonelik sorgusu gönderir. Sunucu aboneliği saklar ve trigger çağrıldığında sonucu eşleşen tüm istemcilere gönderir. Abonelik ID'si istemcilerin abonelikten çıkmasını sağlar.

Rails API için GraphQL'i ne zaman REST yerine tercih edersiniz?

GraphQL, istemciler farklı veri alt kümeleri gerektirdiğinde aşırı veri çekmeyi azaltır; bu durum farklı ekran boyutlarına sahip mobil uygulamalarda yaygındır. Ayrıca tek bir görünüm birden fazla modelden veri gerektirdiğinde birden fazla REST endpoint'i ihtiyacını ortadan kaldırır. REST, tutarlı veri şekilleriyle CRUD ağırlıklı API'ler ve önbelleklemenin kritik olduğu genel API'ler için daha basit kalır.

graphql-ruby'de kimlik doğrulama ve yetkilendirmeyi nasıl yönetirsiniz?

Kimlik doğrulama, GraphQL yürütmesinden önce controller'da gerçekleşir, genellikle Devise, Warden veya JWT doğrulaması ile. Kimliği doğrulanmış kullanıcı context içinde geçirilir. Yetkilendirme çözücülerde veya graphql-ruby'nin tip ve mutasyonlardaki authorized? hook'u aracılığıyla gerçekleşir ve erişim reddedildiğinde GraphQL::ExecutionError fırlatılır.

Daha fazla Ruby on Rails mülakat hazırlığı için GraphQL bilgisini tamamlayan REST API tasarım kalıplarını kapsayan Rails API Mode modülüne bakabilirsiniz.

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Rails ile Üretim GraphQL API'leri Oluşturma: Temel Çıkarımlar

  • graphql-ruby'yi rails generate graphql:install ile kurmak şema, tipler ve routing'i oluşturur
  • Tüm ilişkiler için DataLoader kaynakları kullanmak veritabanı sorgularını toplar ve N+1 performans sorunlarını önler
  • Mutasyonlar, dönüş tipinde açık hata alanları ile ayrı sınıflarda tanımlanır
  • ActionCable aracılığıyla abonelik entegrasyonu, model callback'lerinden veya servis nesnelerinden tetiklenen gerçek zamanlı güncellemeler sağlar
  • Sorguları ve mutasyonları RSpec'te doğrudan şemaya karşı çalıştırarak test edin
  • Kimlik doğrulama controller'a aittir; yetkilendirme kontrolleri çözücüler içinde context[:current_user] kullanılarak gerçekleşir
  • İstemciler esnek veri çekmeye ihtiyaç duyduğunda GraphQL'i tercih edin; tekdüze yanıtlarla basit CRUD API'ler için REST ile devam edin
Günün meydan okuması

Ruby on Rails kodundaki hatayı bulabilir misin?

Gerçek bir kod parçası, gizli bir hata, günde bir deneme. Denemek için hesap gerekmez.

Anthony Fillion-Maillet

Yazan:

Anthony Fillion-Maillet

SharpSkill kurucusu

10 yılı aşkın süredir fullstack geliştirici. SharpSkill’i yönetiyor ve burada yayımlanan her şeyden sorumlu.

19 Eylül 2026 tarihinde güncellendi

Paylaş

İlgili makaleler