• Stars
    star
    1,567
  • Rank 28,463 (Top 0.6 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created over 7 years ago
  • Updated 9 months ago

Reviews

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

Repository Details

📰 A small module that implements GraphQL subscriptions for Node.js

npm version GitHub license

graphql-subscriptions

GraphQL subscriptions is a simple npm package that lets you wire up GraphQL with a pubsub system (like Redis) to implement subscriptions in GraphQL.

You can use it with any GraphQL client and server (not only Apollo).

Installation

npm install graphql-subscriptions graphql or yarn add graphql-subscriptions graphql

This package should be used with a network transport, for example subscriptions-transport-ws.

TypeScript

If you are developing a project that uses this module with TypeScript:

  • ensure that your tsconfig.json lib definition includes "esnext.asynciterable"
  • npm install @types/graphql or yarn add @types/graphql

Getting started with your first subscription

To begin with GraphQL subscriptions, start by defining a GraphQL Subscription type in your schema:

type Subscription {
    somethingChanged: Result
}

type Result {
    id: String
}

Next, add the Subscription type to your schema definition:

schema {
  query: Query
  mutation: Mutation
  subscription: Subscription
}

Now, let's create a simple PubSub instance - it is a simple pubsub implementation, based on EventEmitter. Alternative EventEmitter implementations can be passed by an options object to the PubSub constructor.

import { PubSub } from 'graphql-subscriptions';

export const pubsub = new PubSub();

Now, implement your Subscriptions type resolver, using the pubsub.asyncIterator to map the event you need:

const SOMETHING_CHANGED_TOPIC = 'something_changed';

export const resolvers = {
  Subscription: {
    somethingChanged: {
      subscribe: () => pubsub.asyncIterator(SOMETHING_CHANGED_TOPIC),
    },
  },
}

Subscriptions resolvers are not a function, but an object with subscribe method, that returns AsyncIterable.

Now, the GraphQL engine knows that somethingChanged is a subscription, and every time we use pubsub.publish over this topic - it will publish it using the transport we use:

pubsub.publish(SOMETHING_CHANGED_TOPIC, { somethingChanged: { id: "123" }});

Note that the default PubSub implementation is intended for demo purposes. It only works if you have a single instance of your server and doesn't scale beyond a couple of connections. For production usage you'll want to use one of the PubSub implementations backed by an external store. (e.g. Redis)

Filters

When publishing data to subscribers, we need to make sure that each subscriber gets only the data it needs.

To do so, we can use withFilter helper from this package, which wraps AsyncIterator with a filter function, and lets you control each publication for each user.

withFilter API:

  • asyncIteratorFn: (rootValue, args, context, info) => AsyncIterator<any> : A function that returns AsyncIterator you got from your pubsub.asyncIterator.
  • filterFn: (payload, variables, context, info) => boolean | Promise<boolean> - A filter function, executed with the payload (the published value), variables, context and operation info, must return boolean or Promise<boolean> indicating if the payload should pass to the subscriber.

For example, if somethingChanged would also accept a variable with the ID that is relevant, we can use the following code to filter according to it:

import { withFilter } from 'graphql-subscriptions';

const SOMETHING_CHANGED_TOPIC = 'something_changed';

export const resolvers = {
  Subscription: {
    somethingChanged: {
      subscribe: withFilter(() => pubsub.asyncIterator(SOMETHING_CHANGED_TOPIC), (payload, variables) => {
        return payload.somethingChanged.id === variables.relevantId;
      }),
    },
  },
}

Note that when using withFilter, you don't need to wrap your return value with a function.

Channels Mapping

You can map multiple channels into the same subscription, for example when there are multiple events that trigger the same subscription in the GraphQL engine.

const SOMETHING_UPDATED = 'something_updated';
const SOMETHING_CREATED = 'something_created';
const SOMETHING_REMOVED = 'something_removed';

export const resolvers = {
  Subscription: {
    somethingChanged: {
      subscribe: () => pubsub.asyncIterator([ SOMETHING_UPDATED, SOMETHING_CREATED, SOMETHING_REMOVED ]),
    },
  },
}

Payload Manipulation

You can also manipulate the published payload, by adding resolve methods to your subscription:

const SOMETHING_UPDATED = 'something_updated';

export const resolvers = {
  Subscription: {
    somethingChanged: {
      resolve: (payload, args, context, info) => {
        // Manipulate and return the new value
        return payload.somethingChanged;
      },
      subscribe: () => pubsub.asyncIterator(SOMETHING_UPDATED),
    },
  },
}

Note that resolve methods execute after subscribe, so if the code in subscribe depends on a manipulated payload field, you will need to factor out the manipulation and call it from both subscribe and resolve.

Usage with callback listeners

Your database might have callback-based listeners for changes, for example something like this:

const listenToNewMessages = (callback) => {
  return db.table('messages').listen(newMessage => callback(newMessage));
}

// Kick off the listener
listenToNewMessages(message => {
  console.log(message);
})

The callback function would be called every time a new message is saved in the database. Unfortunately, that doesn't play very well with async iterators out of the box because callbacks are push-based, where async iterators are pull-based.

We recommend using the callback-to-async-iterator module to convert your callback-based listener into an async iterator:

import asyncify from 'callback-to-async-iterator';

export const resolvers = {
  Subscription: {
    somethingChanged: {
      subscribe: () => asyncify(listenToNewMessages),
    },
  },
}

Custom AsyncIterator Wrappers

The value you should return from your subscribe resolver must be an AsyncIterator.

You can use this value and wrap it with another AsyncIterator to implement custom logic over your subscriptions.

For example, the following implementation manipulates the payload by adding some static fields:

import { $$asyncIterator } from 'iterall';

export const withStaticFields = (asyncIterator: AsyncIterator<any>, staticFields: Object): Function => {
  return (rootValue: any, args: any, context: any, info: any): AsyncIterator<any> => {

    return {
      next() {
        return asyncIterator.next().then(({ value, done }) => {
          return {
            value: {
              ...value,
              ...staticFields,
            },
            done,
          };
        });
      },
      return() {
        return Promise.resolve({ value: undefined, done: true });
      },
      throw(error) {
        return Promise.reject(error);
      },
      [$$asyncIterator]() {
        return this;
      },
    };
  };
};

You can also take a look at withFilter for inspiration.

For more information about AsyncIterator:

PubSub Implementations

It can be easily replaced with some other implementations of PubSubEngine abstract class. Here are a few of them:

You can also implement a PubSub of your own, by using the exported abstract class PubSubEngine from this package. By using extends PubSubEngine you use the default asyncIterator method implementation; by using implements PubSubEngine you must implement your own AsyncIterator.

SubscriptionManager @deprecated

SubscriptionManager is the previous alternative for using graphql-js subscriptions directly, and it's now deprecated.

If you are looking for its API docs, refer to a previous commit of the repository

More Repositories

1

apollo-client

🚀  A fully-featured, production ready caching GraphQL client for every UI framework and GraphQL server.
TypeScript
18,905
star
2

apollo-server

🌍  Spec-compliant and production ready JavaScript GraphQL server that lets you develop in a schema-first way. Built for Express, Connect, Hapi, Koa, and more.
TypeScript
13,522
star
3

react-apollo

♻️ React integration for Apollo Client
JavaScript
6,887
star
4

apollo-ios

📱  A strongly-typed, caching GraphQL client for iOS, written in Swift.
Swift
3,737
star
5

apollo-kotlin

🤖  A strongly-typed, caching GraphQL client for the JVM, Android, and Kotlin multiplatform.
Kotlin
3,382
star
6

apollo-tooling

✏️ Apollo CLI for client tooling (Mostly replaced by Rover)
TypeScript
3,042
star
7

apollo

🚀 Open source tools for GraphQL. Central repo for discussion.
JavaScript
2,626
star
8

graphql-tag

A JavaScript template literal tag that parses GraphQL queries
TypeScript
2,275
star
9

subscriptions-transport-ws

🔃 A WebSocket client + server for GraphQL subscriptions
TypeScript
1,524
star
10

apollo-client-devtools

Apollo Client browser developer tools.
TypeScript
1,471
star
11

apollo-link

🔗 Interface for fetching and modifying control flow of GraphQL requests
TypeScript
1,438
star
12

apollo-link-state

✨ Manage your application's state with Apollo!
TypeScript
1,405
star
13

apollo-cache-persist

🎏 Simple persistence for all Apollo Cache implementations
TypeScript
1,363
star
14

fullstack-tutorial

🚀 The Apollo platform tutorial app
TypeScript
1,241
star
15

eslint-plugin-graphql

🚦 Check your GraphQL query strings against a schema.
JavaScript
1,194
star
16

apollo-link-rest

Use existing REST endpoints with GraphQL
TypeScript
783
star
17

router

A configurable, high-performance routing runtime for Apollo Federation 🚀
Rust
737
star
18

federation

🌐  Build and scale a single data graph across multiple services with Apollo's federation gateway.
TypeScript
638
star
19

apollo-fetch

🐶 Lightweight GraphQL client that supports middleware and afterware
TypeScript
576
star
20

apollo-rs

Spec compliant GraphQL Tools in Rust.
Rust
556
star
21

reason-apollo

Reason binding for Apollo Client and React Apollo
Reason
555
star
22

federation-demo

Federation 2 supersedes this demo and this example is no longer the newest. See https://www.apollographql.com/docs/federation/ for migration steps!
JavaScript
504
star
23

ac3-state-management-examples

✨ Learn Apollo Client 3's state management best practices
TypeScript
491
star
24

apollo-tracing

A GraphQL extension for performance tracing
475
star
25

persistgraphql

A build tool for GraphQL projects.
TypeScript
424
star
26

rover

✨🤖 🐶 The CLI for Apollo GraphOS
Rust
389
star
27

gatsby-theme-apollo

💜 Themes that we use to build Gatsby sites at Apollo
JavaScript
371
star
28

apollo-client-nextjs

Apollo Client support for the Next.js App Router
TypeScript
337
star
29

apollo-link-persisted-queries

Persisted Query support with Apollo Link
TypeScript
307
star
30

xcode-graphql

🛠 Xcode add-ons that add syntax highlighting for GraphQL query document files
Shell
276
star
31

apollo-studio-community

🎡  GraphQL developer portal featuring an IDE (Apollo Explorer), auto-documentation, metrics reporting, and more. This repo is for issues, feature requests, and preview docs. 📬
246
star
32

federation-jvm

JVM support for Apollo Federation
Java
229
star
33

supergraph-demo-fed2

🍿 Supergraph demo for Federation 2 and Apollo Router
Shell
155
star
34

apollo-cache-control

A GraphQL extension for cache control
146
star
35

principled-graphql

📈 Best practices for implementing and scaling a data graph
JavaScript
145
star
36

supergraph-demo

🍿 Compose subgraphs into a Federation v1 supergraph at build-time with static composition to power a federated graph router at runtime.
Shell
131
star
37

apollo-feature-requests

🧑‍🚀 Apollo Client Feature Requests | (no 🐛 please).
128
star
38

meteor-integration

🚀 meteor add apollo
JavaScript
108
star
39

spotify-showcase

A Spotify clone that showcases the Apollo GraphQL platform.
TypeScript
106
star
40

frontpage-ios-app

📄 Apollo "hello world" app, for iOS
Swift
101
star
41

space-kit

👩‍🚀 Home base for Apollo's design system: https://space-kit.netlify.com
TypeScript
89
star
42

apollo-scalajs

Use Apollo GraphQL from Scala.js apps!
Scala
88
star
43

invariant-packages

Packages for working with invariant(condition, message) assertions
TypeScript
86
star
44

apollo-federation-subgraph-compatibility

A repo to test subgraph libraries compatibility with the Apollo Federation Specification
TypeScript
73
star
45

starwars-server

JavaScript
72
star
46

blog

📝 Blog website built with Wordpress and Gatsby
JavaScript
68
star
47

iOSTutorial

The tutorial application for the Apollo iOS SDK
Swift
65
star
48

odyssey-lift-off-part1

JavaScript
61
star
49

federation-jvm-spring-example

Apollo Federation JVM example implementation using Spring for GraphQL
Java
56
star
50

vscode-graphql

Apollo GraphQL VS Code extension
TypeScript
49
star
51

apollo-kotlin-tutorial

The code for the Apollo Kotlin Tutorial
Kotlin
49
star
52

docs-examples

Example code supporting the Apollo docs
TypeScript
46
star
53

apollo-kotlin-2-tutorial

The code for the Apollo Android Tutorial
Kotlin
38
star
54

iOSCodegenTemplate

A template for the code you need to set up to get Swift Scripting up and running.
Swift
38
star
55

docs

📚 Apollo's docs framework
MDX
36
star
56

apollo-workbench-vscode

Apollo Workbench is a design tool that facilitates planning changes to your supergraph. It enables you to understand the overall composition and execution of any given query at design time.
TypeScript
36
star
57

react-apollo-error-template

Apollo Client issue reproduction.
JavaScript
33
star
58

apollo-utils

Monorepo of common utilities related to Apollo and GraphQL
TypeScript
32
star
59

federation-rs

Contains source code for Apollo Federation's Rust<--> JavaScript interop
Rust
32
star
60

federation-migration-example

🚀Example app migrated from schema stitching to Apollo federation
JavaScript
32
star
61

odyssey-lift-off-part5-server

Odyssey Lift-off V - Server - Course Companion App
JavaScript
31
star
62

embeddable-explorer

TypeScript
31
star
63

odyssey-lift-off-part5-client

Odyssey Lift-off V - Client - Course Companion App
JavaScript
28
star
64

GraphiQL-Subscriptions-Fetcher

GraphiQL's fetcher that supports GraphQL-Subscriptions with the `subscriptions-transport-ws` package
TypeScript
28
star
65

datasource-rest

A caching data source for REST APIs
TypeScript
28
star
66

supergraph-demo-k8s-graph-ops

Archived: GitOps config repo for an Apollo GraphQL federated graph with a supergraph router and subgraph services deployed to Kubernetes.
Shell
27
star
67

odyssey-lift-off-part2

Odyssey Lift-off Part 2 Course Companion App
JavaScript
25
star
68

apollo-graphql-stream-scenes

This is used for hosting streaming scenes for OBS - for Apollo GraphQL stream
JavaScript
20
star
69

spacex

A re-creation of https://github.com/SpaceXLand/api
TypeScript
18
star
70

odyssey-voyage-I

JavaScript
14
star
71

federation-hotchocolate

HotChocolate support for Apollo Federation
C#
14
star
72

typescript-repo-template

A template for TypeScript projects with pre-configured tooling
TypeScript
14
star
73

odyssey-lift-off-part3

Odyssey Lift-off Part 3 Course Companion App
JavaScript
14
star
74

federation-next

Home of the rust rewrite of federation core (composition & query planning)
Rust
14
star
75

apollo-ios-dev

Apollo iOS Development Repo
Swift
14
star
76

odyssey-lift-off-part4

Odyssey Lift-off Part 4 Course Companion App
JavaScript
13
star
77

subgraph-template-typescript-apollo-server

A Typescript template for Apollo Server as a subgraph using Apollo Federation
TypeScript
13
star
78

community

Apollo community guidelines
JavaScript
13
star
79

design-principles

Where we are defining and collaborating on our Apollo internal design principles (individually and collaboratively). This is a public repo, but intended only for use by Apollo employees.
13
star
80

core-schema-js

Typescript library for processing core schemas
TypeScript
12
star
81

apollo-client-swift-playground

Swift
11
star
82

test-span

Rust
11
star
83

subgraph-template-typescript-apollo-server-boilerplate

A template for a minimal setup Apollo Server 4.x using TypeScript
TypeScript
11
star
84

apollo-ios-pagination

Swift
10
star
85

specs

Apollo Library of Technical Specifications
CSS
10
star
86

apollo-midnight

A VS Code color theme based on Apollo Studio Explorer color palette.
9
star
87

devhub

🔭 Explore all the latest resources for building apps with Apollo
JavaScript
8
star
88

serde_json_bytes

a JSON Value object with strings backed by Bytes, parsed by serde_json
Rust
8
star
89

hack-the-supergraph

JavaScript
8
star
90

next-apollo-example

Template for creating Apollo Client + Next.js reproductions
JavaScript
8
star
91

router-biscuit-plugin

⚠️experimental⚠️ plugin for the router using Biscuit tokens for authorization
Rust
7
star
92

apollo-ios-codegen

Apollo iOS Code Generation
Swift
7
star
93

odyssey-lift-off-lab

Odyssey Lift-off Lab starter repo
JavaScript
7
star
94

zen-observable-ts

Thin wrapper around zen-observable and @types/zen-observable, to support ESM exports
JavaScript
7
star
95

router-template

A general purpose self-hosted Apollo Router template connected to GraphOS
Dockerfile
7
star
96

introspector-gadget

GraphQL introspection utilities
Rust
6
star
97

client-router-e2e-tests

Apollo Client ↔️ Router E2E Test Suite
JavaScript
6
star
98

subgraph-template-rust-async-graphql

A boilerplate template project for building a subgraph with async-graphql
Rust
6
star
99

odyssey-voyage-II-server

The course companion app to Odyssey's Federation series.
JavaScript
5
star
100

apollo-server-starter

A starter/demonstration repo of Apollo Server
JavaScript
5
star