Relay Subscriptions

graphql-ruby-client includes three kinds of support for subscriptions with Relay Modern:

To use it, require subscriptions/createHandler and call the function with your client and optionally, your OperationStoreClient.

See the Subscriptions guide for information about server-side setup.

Pusher

Subscriptions with Pusher require two things:

Pusher client

Pass pusher: to get Subscription updates over Pusher:

// Load the helper function
import { createRelaySubscriptionHandler } from "graphql-ruby-client"

// Prepare a Pusher client
var Pusher = require("pusher-js")
var pusherClient = new Pusher(appKey, options)

// Create a fetchOperation, see below for more details
function fetchOperation(operation, variables, cacheConfig) {
  return fetch(...)
}

// Create a Relay Modern-compatible handler
var subscriptionHandler = createHandler({
  pusher: pusherClient,
  fetchOperation: fetchOperation
})

// Create a Relay Modern network with the handler
var network = Network.create(fetchQuery, subscriptionHandler)

Ably

Subscriptions with Ably require two things:

Ably client

Pass ably: to get Subscription updates over Ably:

// Load the helper function
import { createRelaySubscriptionHandler } from "graphql-ruby-client"

// Load Ably and create a client
const Ably = require("ably")
const ablyClient = new Ably.Realtime({ key: "your-app-key" })

// create a fetchOperation, see below for more details
function fetchOperation(operation, variables, cacheConfig) {
  return fetch(...)
}

// Create a Relay Modern-compatible handler
var subscriptionHandler = createHandler({
  ably: ablyClient,
  fetchOperation: fetchOperation
})

// Create a Relay Modern network with the handler
var network = Network.create(fetchQuery, subscriptionHandler)

ActionCable

With this configuration, subscription queries will be routed to ActionCable.

For example:

// Require the helper function
import { createRelaySubscriptionHandler } from "graphql-ruby-client")
// Optionally, load your OperationStoreClient
var OperationStoreClient = require("./OperationStoreClient")

// Create a Relay Modern-compatible handler
var subscriptionHandler = createRelaySubscriptionHandler({
  cable: cable,
  operations: OperationStoreClient,
})

// Create a Relay Modern network with the handler
var network = Network.create(fetchQuery, subscriptionHandler)

fetchOperation function

The fetchOperation function can be extracted from your fetchQuery function. Its signature is:

// Returns a promise from `fetch`
function fetchOperation(operation, variables, cacheConfig) {
  return fetch(...)
}

For example, Environment.js may look like:

// This function sends a GraphQL query to the server
const fetchOperation = function(operation, variables, cacheConfig) {
  const bodyValues = {
    variables,
    operationName: operation.name,
  }
  const useStoredOperations = process.env.NODE_ENV === "production"
  if (useStoredOperations) {
    // In production, use the stored operation
    bodyValues.operationId = OperationStoreClient.getOperationId(operation.name)
  } else {
    // In development, use the query text
    bodyValues.query = operation.text
  }
  return fetch('http://localhost:3000/graphql', {
    method: 'POST',
    opts: {
      credentials: 'include',
    },
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(bodyValues),
  })
}

// `fetchQuery` uses `fetchOperation`, but returns a Promise of JSON
const fetchQuery = (operation, variables, cacheConfig, uploadables) => {
  return fetchOperation(operation, variables, cacheConfig).then(response => {
    return response.json()
  })
}

// Subscriptions uses the same `fetchOperation` function for initial subscription requests
const subscriptionHandler = createRelaySubscriptionHandler({pusher: pusherClient, fetchOperation: fetchOperation})
// Combine them into a `Network`
const network = Network.create(fetchQuery, subscriptionHandler)

Since OperationStoreClient is in the fetchOperation function, it will apply to all GraphQL operations.