Using GraphQL Subscriptions for Real-Time Data

Reading Time: 8 min read

Introduction

Real-time data is essential for modern web applications that require up-to-the-minute information and seamless user experiences. GraphQL subscriptions provide a powerful way to implement real-time data features in your applications. In this post, we'll explore how to use GraphQL subscriptions to enable real-time data updates, ensuring your application remains responsive and dynamic.

What are GraphQL Subscriptions?

GraphQL subscriptions are a way to maintain an active connection between the client and the server, allowing the server to send real-time updates to the client. This is particularly useful for applications that require live data, such as chat apps, live sports scores, and financial tickers.

Setting Up GraphQL Subscriptions

To get started with GraphQL subscriptions, you need a GraphQL server that supports subscriptions and a client that can handle real-time updates. In this example, we'll use Apollo Server and Apollo Client, two popular libraries in the GraphQL ecosystem.

  1. Setting Up the Server:

    First, install the necessary dependencies:

    npm install apollo-server graphql subscriptions-transport-ws

    Create a simple Apollo Server with subscription support:

    // server.js
    const { ApolloServer, gql } = require('apollo-server')
    const { PubSub } = require('graphql-subscriptions')
     
    const pubsub = new PubSub()
    const MESSAGE_ADDED = 'MESSAGE_ADDED'
     
    const typeDefs = gql`
      type Message {
        id: ID!
        content: String!
      }
     
      type Query {
        messages: [Message!]
      }
     
      type Mutation {
        addMessage(content: String!): Message
      }
     
      type Subscription {
        messageAdded: Message
      }
    `
     
    const resolvers = {
      Query: {
        messages: () => [],
      },
      Mutation: {
        addMessage: (parent, { content }) => {
          const message = { id: Date.now().toString(), content }
          pubsub.publish(MESSAGE_ADDED, { messageAdded: message })
          return message
        },
      },
      Subscription: {
        messageAdded: {
          subscribe: () => pubsub.asyncIterator([MESSAGE_ADDED]),
        },
      },
    }
     
    const server = new ApolloServer({ typeDefs, resolvers })
     
    server.listen().then(({ url }) => {
      console.log(`🚀 Server ready at ${url}`)
    })
  2. Setting Up the Client:

    Install the necessary dependencies:

    npm install @apollo/client graphql subscriptions-transport-ws

    Set up Apollo Client with subscription support:

    // client.js
    import {
      ApolloClient,
      InMemoryCache,
      ApolloProvider,
      useQuery,
      useMutation,
      useSubscription,
      gql,
    } from '@apollo/client'
    import { WebSocketLink } from '@apollo/client/link/ws'
     
    const wsLink = new WebSocketLink({
      uri: 'ws://localhost:4000/graphql',
      options: {
        reconnect: true,
      },
    })
     
    const client = new ApolloClient({
      link: wsLink,
      cache: new InMemoryCache(),
    })
     
    const GET_MESSAGES = gql`
      query GetMessages {
        messages {
          id
          content
        }
      }
    `
     
    const ADD_MESSAGE = gql`
      mutation AddMessage($content: String!) {
        addMessage(content: $content) {
          id
          content
        }
      }
    `
     
    const MESSAGE_ADDED = gql`
      subscription OnMessageAdded {
        messageAdded {
          id
          content
        }
      }
    `
     
    function Messages() {
      const { data } = useSubscription(MESSAGE_ADDED)
      const [addMessage] = useMutation(ADD_MESSAGE)
      const { loading, error, data: queryData } = useQuery(GET_MESSAGES)
     
      if (loading) return <p>Loading...</p>
      if (error) return <p>Error: {error.message}</p>
     
      return (
        <div>
          <ul>
            {queryData.messages.map(({ id, content }) => (
              <li key={id}>{content}</li>
            ))}
            {data && <li>{data.messageAdded.content}</li>}
          </ul>
          <button
            onClick={() =>
              addMessage({ variables: { content: 'Hello, World!' } })
            }
          >
            Add Message
          </button>
        </div>
      )
    }
     
    function App() {
      return (
        <ApolloProvider client={client}>
          <Messages />
        </ApolloProvider>
      )
    }
     
    export default App

Best Practices for Using GraphQL Subscriptions

  1. Efficient Data Management:

    • Use in-memory caching to manage subscription data efficiently and reduce redundant network requests.
  2. Security:

    • Implement proper authentication and authorization to ensure that only authorized clients can subscribe to updates.
  3. Scalability:

    • Consider using a message broker like Redis or Kafka to handle high-throughput subscription data and improve scalability.

Conclusion

GraphQL subscriptions provide a robust way to implement real-time data features in your applications, enhancing user experience by keeping data up-to-date without manual refreshes. By integrating subscriptions into your GraphQL setup, you can build dynamic and responsive applications that meet modern user expectations.

For more detailed information, visit the Apollo GraphQL subscriptions documentation.

Go back Home.