• Stars
    star
    436
  • Rank 99,590 (Top 2 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created about 4 years ago
  • Updated about 1 month ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Realtime GraphQL Live Queries with JavaScript

GraphQL Live Query

Real-Time with any schema or transport.

Why Live Queries? - Read the introduction Post - Learn how Live Query Tracking works



Packages in this Repository

Package Description Stats
@n1ru4l/in-memory-live-query-store Live query implementation. npm version npm downloads
@n1ru4l/graphql-live-query Utilities for live query implementations. npm version npm downloads
@n1ru4l/graphql-live-query-patch-json-patch Reduce live query payload size with JSON patches npm version npm downloads
@n1ru4l/graphql-live-query-patch-jsondiffpatch Reduce live query payload size with @n1ru4l/json-patch-plus npm version npm downloads
@n1ru4l/socket-io-graphql-server GraphQL over Socket.io - Server Middleware npm version npm downloads
@n1ru4l/socket-io-graphql-client GraphQL over Socket.io - Client npm version npm downloads
todo-example-app Todo App with state sync across clients. -

Motivation

There is no mature live query implementation that is not tied to any specific database or SaaS product. This implementation should serve as an example for showcasing how live queries can be added to any GraphQL.js schema with (almost) any GraphQL transport.

GraphQL already has a solution for real-time: Subscriptions. Those are the right tool for responding to events. E.g. triggering a sound or showing a toast message because someone poked you on Facebook. Subscriptions are also often used for updating existing query results on a client that consumes data from the same GraphQL API. Depending on the complexity of that data, cache update code for applying the subscription result can eventually become pretty bloated (!!! especially, for adding and removing list items). Often for developers it is more straight-forward to simply refetch the query once a subscription event is received instead of doing cache voodoo magic.

In contrast to manual cache updates using subscriptions, live queries should feel magical and update the UI with the latest data from the server without having to write any cache update wizardry code on the client.

Concept

A live query is a query operation that is annotated with a @live directive.

query users @live {
  users(first: 10) {
    id
    login
  }
}

A live query is sent to the server (via a transport that supports delivering partial execution results) and registered. The client receives a immediate execution result and furthermore receives additional (partial) execution results once the live query operation was invalidated and therefore the client data became stale.

The client can inform the server that it is no longer interested in the query (unsubscribe the live query operation).

On the server we have a live query invalidation mechanism that is used for determining which queries have become stale, and thus need to be rescheduled for execution.

Instead of sending the whole execution result, the server can diff the previous and the current execution result and only send a delta instruction to the client instead of the whole operation, resulting in less network overhead!

In a future implementation the server might only need to re-execute partial subtrees of a query operation instead of the whole operation.

How does the server know the underlying data of a query operation has changed?

The reference InMemoryLiveQueryStore implementation uses an ad hoc resource tracker, where an operation subscribes to the specific topics computed out of the query and resolved resources during the latest query execution.

A resource (in terms of the reference implementation) is described by a root query field schema coordinate (such as Query.viewer or Query.users), a root query field with id argument (Query.user(id:"1")) or a resource identifier (such as User:1). The latter is by default composed out of the resource typename and the non nullable id field of the given GraphQL type.

For the following type:

type User {
  id: ID!
  name: String!
}

Legitimate resource identifiers could be User:1, User:2, User:dfsg12. Where the string after the first colon describes the id of the resource.

In case a resource has become stale it can be invalidated using the InMemoryLiveQueryStore.invalidate method, which results in all operations that select a given resource to be scheduled for re-execution.

Practical example:

// somewhere inside a userChangeLogin mutation resolver
user.login = "n1ru4l";
user.save();
liveQueryStore.invalidate([
  // Invalidate all operations whose latest execution result contains the given user
  `User:${user.id}`,
  // Invalidate query operations that select the Query,user field with the id argument
  `Query.user(id:"${user.id}")`,
  // invalidate a list of all users (redundant with previous invalidations)
  `Query.users`,
]);

Those invalidation calls could be done manually in the mutation resolvers or on more global reactive level e.g. as a listener on a database write log. The possibilities are infinite. πŸ€”

For scaling horizontally the independent InMemoryLiveQueryStore instances can be wired together via a PubSub system such as Redis.

How are the updates sent/applied to the client?

The transport layer can be any transport that allows sending partial execution results to the client.

Most GraphQL clients (including GraphiQL, Apollo, Relay and Urql) have support for Observable or async iterable data structures which are perfect for describing both Subscription and Live Queries. Ideally a GraphQL Live Query implementation uses a AsyncIterable or Observable for pushing the latest query data to the client framework that consumes the data.

List of compatible transports/servers

List of known and tested compatible transports/servers. The order is alphabetical. Please feel free to add additional compatible transports to the list!

Package Transport Version Downloads
@n1ru4l/socket-io-graphql-server GraphQL over Socket.io (WebSocket/HTTP Long Polling) npm version npm downloads
graphql-helix GraphQL over HTTP (IncrementalDelivery/SSE) npm version npm downloads
graphql-ws GraphQL over WebSocket (WebSocket) npm version npm downloads

More Repositories

1

envelop

Envelop is a lightweight library allowing developers to easily develop, share, collaborate and extend their GraphQL execution layer. Envelop is the missing GraphQL plugin system.
TypeScript
785
star
2

use-async-effect

React hook for async effects powered by generator functions.
TypeScript
195
star
3

graphql-bleeding-edge-playground

Demonstration of queries/mutations/defer/stream/subscriptions/live
TypeScript
137
star
4

graphql-schema-generator-rest

Generate your GraphQL schema from type definitions
JavaScript
97
star
5

graphiql-apollo-tracing

poc graphiql with apollo-tracing support
JavaScript
51
star
6

graphql-public-schema-filter

Filter your GraphQL graph into a subgraph. Code-first & SDL-first!
TypeScript
51
star
7

graphql-codegen-relay-plugins

Use the power of the relay-compiler with every GraphQL project!
TypeScript
39
star
8

relay-compiler-repl

Convince your team that you should use the relay-compiler πŸ˜‰
TypeScript
34
star
9

graphql-live-chat

Chat built with GraphQL Live Subscriptions.
TypeScript
28
star
10

push-pull-async-iterable-iterator

Create an AsyncIterableIterator from anything while handling back-pressure!
TypeScript
23
star
11

character-overlay

Web App for adding an OBS overlay with character information such as name, picture, and health for your favorite role-playing game.
TypeScript
22
star
12

react-in-center-of-screen

Determine if a list item is in the center of your viewport https://codesandbox.io/s/1vw1q2288q
JavaScript
14
star
13

react-use-transition

TypeScript
14
star
14

ember-cli-css-preprocess

Process your stylesheets using various preprocessors like Sass or PostCSS. Looking for new maintainers!
JavaScript
13
star
15

vue-component-database

An online code editor for Vue Single File Components
Vue
11
star
16

bundle-anywhere

TypeScript
10
star
17

toposort

TypeScript toposort
TypeScript
8
star
18

cv-image-grid-detection

JavaScript
7
star
19

ember-card-stacks

Card Stacks inspired by https://tympanus.net/Development/CardStackEffects/
JavaScript
6
star
20

hive-workshop

GraphQL Hive Workshop Material
TypeScript
6
star
21

graphql-operation-merger

A tiny opinionated graphql operation merger
TypeScript
5
star
22

dsa-wiki-crawler

TypeScript
4
star
23

react-time-ago

Display formatted date strings in real-time
JavaScript
4
star
24

pokemon-tcg-deck-scraper-api

JavaScript
4
star
25

ssm-parameter-env

Supply your environment with the AWS Systems Manager Parameter Store
TypeScript
4
star
26

manga-exporter

Collection of utilities for extracting unlicensed community translated mangas from websites into eReader (Kindle) friendly format.
TypeScript
4
star
27

envelop-demo

TypeScript
3
star
28

psql-import-action

Github Action for importing a Postgres Database Dump
Shell
3
star
29

slonik-utilities

Utilities for the PostgreSQL Client Slonik
TypeScript
3
star
30

yoga-grats-demo

TypeScript
2
star
31

docker-image-node-10-with-docker-and-compose

Made for CI
Shell
1
star
32

pg-advisary-lock-check

TypeScript
1
star
33

serverless-codepipeline-slack-notifier

Publish Codepipeline Status Updates to a Slack Channel
JavaScript
1
star
34

n1ru4l

1
star
35

spotify-player-android-sdk

Shell
1
star
36

ember-cli-postcss-fixed

DEPRECATED PLEASE USE ember-cli-css-preprocess
JavaScript
1
star
37

my-library-boilerplate

i keep copy pasting this...
JavaScript
1
star
38

react-native-video-compress-example

Objective-C
1
star
39

graphql-tools-commonjs-import-repro

https://github.com/ardatan/graphql-tools/discussions/4581#discussioncomment-3329673
JavaScript
1
star
40

hive-github-workflow-example

I use this for testing graphql-hive GitHub integrations :)
1
star
41

temperature_converter

Rust
1
star
42

yet-another-react-boilerplate

πŸš€ Universal React Boilerplate. Using React Router, React Helmet and Apollo Client
JavaScript
1
star
43

node-sqlite3

Asynchronous, non-blocking SQLite3 bindings for Node.js
PLpgSQL
1
star
44

docker-python-node-audio-processing

Dockerfile
1
star
45

bob

Build tool used in libraries maintained by The Guild
JavaScript
1
star