Build real-time GraphQL applications using Action Cable channels with the GraphQL::Channel module for WebSocket handling and subscriptions.
The GraphQL::Channel module enables GraphQL over WebSockets through Action Cable, providing real-time subscriptions and live query updates. It manages subscription lifecycles, WebSocket connections, and broadcast handling.
class GraphqlChannel < ApplicationCable::Channel include GraphQL::Channel # As a string (lazy loaded) self.gql_schema = 'GraphQL::AppSchema' # Or as a class reference self.gql_schema = GraphQL::AppSchemaend
If no schema is specified, the channel will attempt to find a schema matching your application name (e.g., GraphQL::AppSchema for an app named App).
The origin: self parameter is vital for subscriptions to work correctly. It allows the subscription provider to transmit updates back to the correct channel instance.
An after_unsubscribe callback ensures subscriptions are cleaned up (lib/rails/graphql/railties/channel.rb:18-21):
included do # Set it up a callback after unsubscribed so that all the subscriptions # can be properly unsubscribed after_unsubscribe :gql_clear_subscriptionsend
The channel automatically parses variables (lib/rails/graphql/railties/channel.rb:114-123):
def gql_variables(data, variables = nil) variables ||= data['variables'] case variables when ::ActionController::Parameters then variables.permit!.to_h when String then variables.present? ? JSON.parse(variables) : {} when Hash then variables else {} endend
class GraphqlChannel < ApplicationCable::Channel include GraphQL::Channel def subscribed logger.info "Client #{connection.connection_identifier} subscribed" end def unsubscribed logger.info "Client #{connection.connection_identifier} unsubscribed with #{gql_subscriptions.count} active subscriptions" end protected def gql_merge_subscriptions(request) super logger.debug "Active subscriptions: #{gql_subscriptions.keys}" endend
require 'rails_helper'RSpec.describe GraphqlChannel, type: :channel do let(:user) { create(:user) } before do stub_connection(current_user: user) end it 'successfully subscribes' do subscribe expect(subscription).to be_confirmed end it 'executes GraphQL queries' do subscribe perform :execute, query: '{ currentUser { id } }' expect(transmissions.last).to include( 'result' => hash_including('data'), 'more' => false ) end it 'tracks subscriptions' do subscribe perform :execute, query: 'subscription { messageAdded { id } }' expect(subscription.gql_subscriptions).not_to be_empty endend