useLiveQuery

useLiveQuery

Package nameWeekly DownloadsVersionLicenseUpdated
@envelop/live-queryDownloadsVersionLicenseOct 16th, 2023

@envelop/live-query

The easiest way of adding live queries to your GraphQL server!

Push new data to your clients automatically once the data selected by a GraphQL operation becomes stale by annotating your query operation with the @live directive.

query UserProfile @live {
  me {
    id
    login
    bio
  }
}

The invalidation mechanism is based on GraphQL ID fields and schema coordinates. Once a query operation has been invalidated, the query is re-executed and the result is pushed to the client.

Installation

yarn add @envelop/live-query @n1ru4l/in-memory-live-query-store

Usage Example

makeExecutableSchema from graphql-tools

import { execute, parse, specifiedRules, subscribe, validate } from 'graphql'
import { envelop, useEngine, useExtendContext, useSchema } from '@envelop/core'
import { useLiveQuery } from '@envelop/live-query'
import { makeExecutableSchema } from '@graphql-tools/schema'
import { InMemoryLiveQueryStore } from '@n1ru4l/in-memory-live-query-store'
 
const schema = makeExecutableSchema({
  typeDefs: [
    /* GraphQL */ `
      type Query {
        greetings: [String!]
      }
    `,
    GraphQLLiveDirectiveSDL
  ],
  resolvers: {
    Query: {
      greetings: (_, __, context) => context.greetings
    }
  }
})
 
const liveQueryStore = new InMemoryLiveQueryStore()
 
const greetings = ['Hello', 'Hi', 'Ay', 'Sup']
// Shuffle greetings and invalidate queries selecting Query.greetings every second.
setInterval(() => {
  const firstElement = greetings.pop()
  greetings.unshift(firstElement)
  liveQueryStore.invalidate('Query.greetings')
}, 1000)
 
const getEnveloped = envelop({
  plugins: [
    useEngine({ parse, validate, specifiedRules, execute, subscribe }),
    useSchema(schema),
    useLiveQuery({ liveQueryStore }),
    useExtendContext(() => ({ greetings }))
    /* other plugins */
  ]
})

GraphQLSchema from graphql

You need to pass the GraphQLLiveDirective to the list of directives:

import { GraphQLSchema } from 'graphql'
import { GraphQLLiveDirective } from '@envelop/live-query'
 
const schema = new GraphQLSchema({
  directives: [...specifiedDirectives, GraphQLLiveDirective]
})

Applying a patch middleware

By using a patch middleware you can significantly reduce the size of the GraphQL execution result payload that is sent over the wire from the server to the client. We recommend using the @n1ru4l/graphql-live-query-patch-jsondiffpatch patch generator. You can learn more about it here.

yarn add @n1ru4l/graphql-live-query-patch-jsondiffpatch
import { applyLiveQueryJSONDiffPatchGenerator } from '@n1ru4l/graphql-live-query-patch-jsondiffpatch'
import { InMemoryLiveQueryStore } from '@n1ru4l/in-memory-live-query-store'
 
const liveQueryStore = new InMemoryLiveQueryStore()
 
const plugin = useLiveQuery({
  liveQueryStore,
  applyLiveQueryPatchGenerator: applyLiveQueryJSONDiffPatchGenerator
})

Further information

This plugin requires you to use a graphql transports that supports usage of the @defer and @stream directives, as it is built upon the same concepts (return an AsyncIterable from execute).

The following transports have been successfully tested:

PackageTransportVersionDownloads
@n1ru4l/socket-io-graphql-serverGraphQL over Socket.io (WebSocket/HTTP Long Polling)npm versionnpm downloads
graphql-helixGraphQL over HTTP (IncrementalDelivery/SSE)npm versionnpm downloads
graphql-wsGraphQL over WebSocket (WebSocket)npm versionnpm downloads
graphql-sseGraphQL over Server-Sent Events (SSE)npm versionnpm downloads

For more details check out the live query repository or the introduction blog post.

There is also a full schema example available.