GraphQL real-time con Subscriptions

Problema

Actualización real time

Poll

Push

Solución

Subscriptions

RFC de Facebook: github.com/facebook/graphql/blob/master/rfcs/Subscriptions.md

 

Implementación de Apollo

subscription onCardSelected($gameId: Int!) {
  cardSelected(gameId: $gameId) {
    id
    selected
  }
}
type Subscription {
  cardSelected(gameId: Int!): Card
}

Server

PubSub

import { PubSub } from 'graphql-subscriptions'
export const pubsub = new PubSub()
pubsub.publish('cardSelected', card)

Subscriptions Manager

import { SubscriptionManager } from 'graphql-subscriptions'

const subscriptionManager = new SubscriptionManager({
  schema,
  pubsub,
  setupFunctions: {
    cardSelected: (options, args) => ({
      cardSelected: {
        filter: card => card.game_id === Number(args.gameId)
      }
    })
  }
})

Websocket Server

import { createServer } from 'http'
import { SubscriptionServer } from 'subscriptions-transport-ws'

const websocketServer = createServer((request, response) => {
  response.writeHead(404)
  response.end()
})

websocketServer.listen(5000, () => console.log(
  'Websocket Server is now running on http://localhost:5000'
))

const subscriptionsServer = new SubscriptionServer(
  {
    subscriptionManager: subscriptionManager
  },
  {
    server: websocketServer
  }
)

Under/over fetching

Stateful

Eventos fuera de GraphQL

Cliente

Websocket Client

import {
  SubscriptionClient,
  addGraphQLSubscriptions
} from 'subscriptions-transport-ws'

const wsClient = new SubscriptionClient('ws://localhost:5000/', {
  reconnect: true
})

/* ... */

const networkInterfaceWithSubscriptions = addGraphQLSubscriptions(
  networkInterface,
  wsClient
)

Higher Order Component

graphql(Query, {
  props: props => {
    return {
      ...props,
      subscribeToCardSelected: params => {
        return props.data.subscribeToMore({
          document: CardsSubscription,
          variables: {
            gameId: params.gameId
          },
          updateQuery: (prev, { subscriptionData }) => {
            // En base a `prev` y lo que devolvió la subscription,
            // construir el `newGame`
            return { game: newGame }
          }
        })
      }
    }
  }
})(Component)
componentWillReceiveProps (newProps) {
  if (this.props.data.loading && !newProps.data.loading) {
    newProps.subscribeToCardSelected({
      gameId: this.props.gameId
    })
  }
}

Demo

GraphQL real-time con Subscriptions

By Julio Olivera

GraphQL real-time con Subscriptions

  • 1,137