0

I am using rails 6.1 graphql gem with Apollo to execute a subscription. It works for normal queries and mutations but rails complains about subscriptions.

In my frontend:

const cable = ActionCable.createConsumer( `${process.env.GATSBY_CABLE_URL}/cable?token=${localStorage.getItem('apiToken')}`, ); const actionCableLink = new ActionCableLink({ cable }); 

GraphQL channel in rails

# Channel used by the graphql schema class GraphqlChannel < ApplicationCable::Channel rescue_from StandardError, with: :report_error @op_name # To be called when a consumer subscribes to the GraphQL channel (ie when a user first opens the application). def subscribed # Store all GraphQL subscriptions the consumer is listening for on this channel @subscription_ids = [] end # To be called when a subscribed consumer registers for a subscription event on this channel. # This will be called once for every event the frontend wants to be notified about. def execute(data) query = data['query'] variables = ensure_hash(data['variables']) @op_name = data['operationName'] operation_name = data['operationName'] puts "Executing #{operation_name}" # puts "execute sub with query #{query}" context = { # Re-implement whatever context methods you need # in this channel or ApplicationCable::Channel # current_user: current_user, # Make sure the channel is in the context channel: self # https://medium.com/@jerridan/implementing-graphql-subscriptions-in-rails-and-react-9e05ca8d6b20 # Note that current_application_context has been added to the context object. # As I mentioned earlier, the Connection instance will be the parent of the GraphqlChannel instance, # so we can get any authorization details that were set in the Connection here. # current_application_context: connection.current_application_context } puts "executing schema query is a #{query.class}" result = ContentManagementSchema.execute({ query: query, context: context, variables: variables, operation_name: operation_name }) payload = { result: result.to_h, more: result.subscription? } puts "result is #{result}" # Track the subscription here so we can remove it # on unsubscribe. @subscription_ids << result.context[:subscription_id] if result.context[:subscription_id] transmit(payload) end # To be called when a consumer unsubscribes from the GraphQL channel (ie when a user closes the application). def unsubscribed # Delete all of the consumer's subscriptions from the GraphQL Schema @subscription_ids.each do |sid| ContentManagementSchema.subscriptions.delete_subscription(sid) end end private def report_error(e) puts "Error in graphql channel: #{e} - Op: #{@op_name}" end def ensure_hash(ambiguous_param) case ambiguous_param when String if ambiguous_param.present? ensure_hash(JSON.parse(ambiguous_param)) else {} end when Hash, ActionController::Parameters ambiguous_param when nil {} else raise ArgumentError, "Unexpected parameter: #{ambiguous_param}" end end end 

What happens is that in rails console I get:

 Executing PageComments 9:51:43 AM web.1 | executing schema query is a String 9:51:43 AM web.1 | Error in graphql channel: Query string argument should be a String, got Hash instead. - Op: SchedulePublishingStatus 9:51:43 AM web.1 | Error in graphql channel: Query string argument should be a String, got Hash instead. - Op: PageComments 

I searched for the error which I found in https://github.com/rmosolgo/graphql-ruby/blob/master/lib/graphql/query.rb which, unsurprisingly says that the query is a hash not a string. I don't really know how that is possible or how I can change this since I use apollos useSubscription hook in my frontend code:

 const { loading, error: subscriptionError } = useSubscription(PAGE_COMMENTS, { variables: { pageId }, onSubscriptionData: (res) => { setComments(res.subscriptionData.data.pageComments); }, }); 
 export const PAGE_COMMENTS = gql` subscription PageComments($pageId: ID) { pageComments(pageId: $pageId) { id body createdAt user { id email } } } `; 
1
  • im not sure if this can solve that problem, sending the params like this:result = ContentManagementSchema.execute(query, context: context, variables: variables, operation_name: operation_name) Commented Jan 5, 2023 at 0:25

1 Answer 1

3

I found the issue. Not sure what the API differences are, but I change the call from

 result = ContentManagementSchema.execute({ query: query, context: context, variables: variables, operation_name: operation_name }) 

to

 result = ContentManagementSchema.execute(query, variables: variables, context: context, operation_name: operation_name) `` and it works now. 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.