Rails GraphQL API di 2026: graphql-ruby, Subscriptions, dan Pertanyaan Interview
Bangun GraphQL API siap produksi dengan Rails 8 dan graphql-ruby. Desain schema, mutations, subscriptions dengan ActionCable, dan persiapan interview.

GraphQL telah menjadi pilihan utama untuk API yang membutuhkan pengambilan data fleksibel, dan graphql-ruby menghadirkan kemampuan ini ke Rails dengan integrasi ActiveRecord yang erat. Rails 8, yang dirilis akhir 2024, berpasangan dengan baik bersama graphql-ruby 2.4, yang memperkenalkan penanganan subscription yang lebih baik dan lazy execution yang ditingkatkan untuk pencegahan N+1.
Gem graphql-ruby menyediakan implementasi GraphQL lengkap: definisi schema dengan DSL Ruby, inferensi tipe otomatis dari model ActiveRecord, DataLoader bawaan untuk batching, dan integrasi ActionCable untuk subscriptions real-time.
Menyiapkan graphql-ruby di Aplikasi Rails 8
Generator gem membuat struktur schema awal dan memasang endpoint GraphQL. Mulai dengan gem dan jalankan generator install untuk membuat scaffold file dasar.
# Gemfile
gem 'graphql', '~> 2.4'# Terminal
bundle install
rails generate graphql:installGenerator membuat app/graphql/ dengan file schema, base types, dan direktori mutations. Ini juga menambahkan route di /graphql dan secara opsional memasang GraphiQL untuk pengembangan.
# app/graphql/sharpskill_schema.rb
class SharpskillSchema < GraphQL::Schema
mutation(Types::MutationType)
query(Types::QueryType)
subscription(Types::SubscriptionType)
# Gunakan DataLoader bawaan untuk pencegahan N+1
use GraphQL::Dataloader
# Diperlukan untuk subscriptions
use GraphQL::Subscriptions::ActionCableSubscriptions
endFile schema bertindak sebagai titik masuk. Ini mendeklarasikan tipe mana yang menangani queries, mutations, dan subscriptions, serta mendaftarkan middleware seperti DataLoader.
Mendefinisikan Types dan Resolvers untuk Model Rails
Setiap model ActiveRecord yang muncul di API membutuhkan tipe GraphQL yang sesuai. Tipe mendefinisikan field mana yang diekspos dan bagaimana mereka di-resolve.
# 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
# Asosiasi dengan batching otomatis via DataLoader
field :posts, [Types::PostType], null: false
def posts
dataloader.with(Sources::ActiveRecordCollection, Post, :user_id).load(object.id)
end
end
endPanggilan dataloader.with mengelompokkan beberapa pengambilan posts ke dalam satu query SQL. Tanpa DataLoader, query yang meminta 50 user beserta posts mereka akan mengeksekusi 51 query. Dengan DataLoader, hanya 2 query yang dijalankan.
# 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
endPola ini muncul di setiap proyek graphql-ruby yang serius. Dokumentasi resmi DataLoader mencakup kasus penggunaan tambahan seperti caching dan nested sources.
Membangun Queries dengan Arguments dan Filtering
QueryType mendefinisikan field root yang tersedia untuk klien. Arguments memungkinkan filtering dan pagination.
# 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
endMetode resolver menerima keyword arguments yang cocok dengan definisi field. Mengembalikan nil dari field nullable adalah valid; melempar error dari field non-null memicu respons error GraphQL.
Siap menguasai wawancara Ruby on Rails Anda?
Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.
Mutations: Membuat dan Memperbarui Record
Mutations mengikuti konvensi yang lebih ketat daripada queries. Setiap mutation berada di kelasnya sendiri dan mengembalikan tipe payload yang menyertakan hasil dan error apa pun.
# 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
endcontext[:current_user] berasal dari controller. Autentikasi terjadi sebelum layer GraphQL, biasanya menggunakan Devise atau library JWT.
# 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
endKontrol akses di dalam resolvers memeriksa context[:current_user] dan melempar GraphQL::ExecutionError ketika tidak diizinkan. Panduan otorisasi graphql-ruby menjelaskan pola otorisasi tingkat field dan tingkat tipe.
Update Real-Time dengan GraphQL Subscriptions dan ActionCable
Subscriptions memungkinkan klien menerima pembaruan ketika event sisi server terjadi. Rails ActionCable menangani koneksi WebSocket, dan graphql-ruby berintegrasi melalui 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 # Object yang diteruskan dari trigger
end
end
endMemicu subscription terjadi dari mana saja di aplikasi, biasanya dalam model callback atau 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
endChannel ActionCable yang menangani subscriptions GraphQL disertakan bersama gem.
# 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
endDi sisi klien, library seperti Apollo Client atau urql terhubung ke WebSocket ActionCable dan mengelola state subscription. Untuk persiapan interview tentang mekanika ActionCable, lihat modul ActionCable & WebSockets.
Testing GraphQL API dengan RSpec
Menguji GraphQL API memerlukan eksekusi queries terhadap schema dan assertion pada struktur dan data respons.
# 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
endTes mutation memverifikasi jalur sukses dan error validasi.
# 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
endUntuk lebih lanjut tentang pola testing Rails, lihat modul Testing dengan RSpec.
Pertanyaan Interview GraphQL Umum untuk Developer Rails
Pewawancara yang menguji pengetahuan GraphQL dalam konteks Rails sering fokus pada masalah implementasi praktis daripada teori tipe abstrak.
Bagaimana cara mencegah query N+1 di graphql-ruby?
Gunakan DataLoader dengan custom sources. Definisikan kelas source yang mengelompokkan panggilan database, dan panggil dataloader.with(SourceClass, args).load(id) di resolvers. DataLoader mengumpulkan semua ID yang diminta dalam satu eksekusi GraphQL dan mengambilnya dalam satu query.
Apa perbedaan antara query dan mutation?
Semantik: queries membaca data dan tidak boleh memiliki efek samping. Mutations memodifikasi data dan mungkin memiliki efek samping. GraphQL menjamin eksekusi paralel untuk field query dan eksekusi sekuensial untuk field mutation, sehingga dua mutation dalam request yang sama dieksekusi berurutan.
Bagaimana subscriptions bekerja di Rails?
Subscriptions menggunakan ActionCable untuk koneksi WebSocket. Klien mengirim query subscription melalui WebSocket. Server menyimpan subscription dan, ketika trigger dipanggil, mendorong hasil ke semua klien yang cocok. ID subscription memungkinkan klien untuk unsubscribe.
Kapan memilih GraphQL daripada REST untuk Rails API?
GraphQL mengurangi over-fetching ketika klien membutuhkan subset data yang berbeda, yang umum di aplikasi mobile dengan berbagai ukuran layar. Ini juga menghilangkan kebutuhan untuk multiple REST endpoints ketika satu view memerlukan data dari beberapa model. REST tetap lebih sederhana untuk API yang berat CRUD dengan bentuk data konsisten dan untuk API publik di mana caching sangat penting.
Bagaimana menangani autentikasi dan otorisasi di graphql-ruby?
Autentikasi terjadi di controller sebelum eksekusi GraphQL, biasanya melalui Devise, Warden, atau verifikasi JWT. User yang terautentikasi diteruskan dalam context. Otorisasi terjadi di resolvers atau melalui hook authorized? graphql-ruby pada types dan mutations, melempar GraphQL::ExecutionError ketika akses ditolak.
Untuk lebih banyak persiapan interview Ruby on Rails, lihat modul Rails API Mode, yang mencakup pola desain REST API yang melengkapi pengetahuan GraphQL.
Mulai berlatih!
Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.
Membangun GraphQL API Produksi dengan Rails: Poin-Poin Penting
- Instal graphql-ruby dengan
rails generate graphql:installuntuk membuat scaffold schema, types, dan routing - Gunakan DataLoader sources untuk semua asosiasi untuk mengelompokkan query database dan mencegah masalah performa N+1
- Definisikan mutations di kelas terpisah dengan field error eksplisit di tipe return
- Integrasikan subscriptions via ActionCable untuk update real-time, memicu dari model callbacks atau service objects
- Uji queries dan mutations dengan mengeksekusinya langsung terhadap schema di RSpec
- Autentikasi berada di controller; pemeriksaan otorisasi terjadi di dalam resolvers menggunakan
context[:current_user] - Pilih GraphQL ketika klien membutuhkan pengambilan data fleksibel; tetap gunakan REST untuk API CRUD sederhana dengan respons seragam
Bisakah kamu menemukan bug di Ruby on Rails?
Satu potongan kode nyata, satu bug tersembunyi, satu percobaan per hari. Tanpa akun untuk mencoba.

Ditulis oleh
Anthony Fillion-MailletPendiri SharpSkill
Developer fullstack selama lebih dari 10 tahun. Ia menjalankan SharpSkill dan bertanggung jawab atas semua yang diterbitkan di sini.
Diperbarui 19 September 2026
Bagikan
Artikel terkait

Background Jobs Rails di 2026: Sidekiq vs Good Job dan Pertanyaan Interview
Panduan lengkap memilih queue backend untuk Rails: perbandingan Sidekiq 8.x, Good Job 4.x, dan Solid Queue dengan fokus pada throughput, fitur, dan pertanyaan interview teknis.

Rails Active Storage 2026: Upload File, Integrasi S3, dan Pertanyaan Interview
Panduan lengkap Rails Active Storage untuk upload file, integrasi Amazon S3, dan persiapan pertanyaan interview Ruby on Rails.

Rails Stimulus dan Importmaps 2026: JavaScript Modern Tanpa Build Tools
Stimulus dan Importmaps di Rails 8.1 memungkinkan penulisan JavaScript modern tanpa bundler. Tutorial ini membahas controller, action, target, dan package npm.