{"id":13433302,"url":"https://github.com/apollographql/graphql-subscriptions","last_synced_at":"2025-05-11T05:48:27.759Z","repository":{"id":42023490,"uuid":"66106110","full_name":"apollographql/graphql-subscriptions","owner":"apollographql","description":":newspaper: A small module that implements GraphQL subscriptions for Node.js","archived":false,"fork":false,"pushed_at":"2024-11-11T21:51:02.000Z","size":198,"stargazers_count":1607,"open_issues_count":54,"forks_count":132,"subscribers_count":60,"default_branch":"master","last_synced_at":"2025-05-01T04:35:50.811Z","etag":null,"topics":["graphql","graphql-subscriptions","real-time"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/apollographql.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-08-19T19:08:00.000Z","updated_at":"2025-04-17T08:45:27.000Z","dependencies_parsed_at":"2023-11-14T23:27:48.008Z","dependency_job_id":"4921bc65-dae0-49fc-9f4c-91818f840878","html_url":"https://github.com/apollographql/graphql-subscriptions","commit_stats":{"total_commits":196,"total_committers":55,"mean_commits":"3.5636363636363635","dds":0.8367346938775511,"last_synced_commit":"b88039743a1497f829ec4b27ed31d497c81e5ce3"},"previous_names":["apollostack/graphql-subscriptions"],"tags_count":36,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apollographql%2Fgraphql-subscriptions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apollographql%2Fgraphql-subscriptions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apollographql%2Fgraphql-subscriptions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apollographql%2Fgraphql-subscriptions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/apollographql","download_url":"https://codeload.github.com/apollographql/graphql-subscriptions/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252843656,"owners_count":21812923,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["graphql","graphql-subscriptions","real-time"],"created_at":"2024-07-31T02:01:23.839Z","updated_at":"2025-05-08T02:32:25.681Z","avatar_url":"https://github.com/apollographql.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","Uncategorized"],"sub_categories":["Uncategorized"],"readme":"[![npm version](https://badge.fury.io/js/graphql-subscriptions.svg)](https://badge.fury.io/js/graphql-subscriptions) [![GitHub license](https://img.shields.io/github/license/apollostack/graphql-subscriptions.svg)](https://github.com/apollographql/graphql-subscriptions/blob/master/LICENSE)\n\n# graphql-subscriptions\n\nGraphQL subscriptions is a simple npm package that lets you wire up GraphQL with a pubsub system (like Redis) to implement subscriptions in GraphQL.\n\nYou can use it with any GraphQL client and server (not only Apollo).\n\n### Installation\n\n`npm install graphql-subscriptions graphql` or `yarn add graphql-subscriptions graphql`\n\n\u003e This package should be used with a network transport, for example [subscriptions-transport-ws](https://github.com/apollographql/subscriptions-transport-ws).\n\n### TypeScript\n\nIf you are developing a project that uses this module with TypeScript:\n\n- ensure that your `tsconfig.json` `lib` definition includes `\"es2018.asynciterable\"`\n- `npm install @types/graphql` or `yarn add @types/graphql`\n\n### Getting started with your first subscription\n\nTo begin with GraphQL subscriptions, start by defining a GraphQL `Subscription` type in your schema:\n\n```graphql\ntype Subscription {\n  somethingChanged: Result\n}\n\ntype Result {\n  id: String\n}\n```\n\nNext, add the `Subscription` type to your `schema` definition:\n\n```graphql\nschema {\n  query: Query\n  mutation: Mutation\n  subscription: Subscription\n}\n```\n\nNow, 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\nto the `PubSub` constructor.\n\n```js\nimport { PubSub } from \"graphql-subscriptions\";\n\nexport const pubsub = new PubSub();\n```\n\nIf you're using TypeScript you can use the optional generic parameter for added type-safety:\n\n```ts\nimport { PubSub } from \"graphql-subscriptions\";\n\nconst pubsub = new PubSub\u003c{\n  EVENT_ONE: { data: number };\n  EVENT_TWO: { data: string };\n}\u003e();\n\npubsub.publish(\"EVENT_ONE\", { data: 42 });\npubsub.publish(\"EVENTONE\", { data: 42 }); // ! ERROR\npubsub.publish(\"EVENT_ONE\", { data: \"42\" }); // ! ERROR\npubsub.publish(\"EVENT_TWO\", { data: \"hello\" });\n\npubsub.subscribe(\"EVENT_ONE\", () =\u003e {});\npubsub.subscribe(\"EVENTONE\", () =\u003e {}); // ! ERROR\npubsub.subscribe(\"EVENT_TWO\", () =\u003e {});\n```\n\nNext implement your Subscriptions type resolver using the `pubsub.asyncIterableIterator` to map the event you need:\n\n```js\nconst SOMETHING_CHANGED_TOPIC = \"something_changed\";\n\nexport const resolvers = {\n  Subscription: {\n    somethingChanged: {\n      subscribe: () =\u003e pubsub.asyncIterableIterator(SOMETHING_CHANGED_TOPIC),\n    },\n  },\n};\n```\n\n\u003e Subscriptions resolvers are not a function, but an object with `subscribe` method, that returns `AsyncIterable`.\n\nThe GraphQL engine now knows that `somethingChanged` is a subscription, and every time we use `pubsub.publish` it will publish content using our chosen transport layer:\n\n```js\npubsub.publish(SOMETHING_CHANGED_TOPIC, { somethingChanged: { id: \"123\" } });\n```\n\n\u003e 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.\n\u003e For production usage you'll want to use one of the [PubSub implementations](#pubsub-implementations) backed by an external store. (e.g. Redis)\n\n### Filters\n\nWhen publishing data to subscribers, we need to make sure that each subscriber gets only the data it needs.\n\nTo 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.\n\n`withFilter` API:\n\n- `asyncIteratorFn: (rootValue, args, context, info) =\u003e AsyncIterator\u003cany\u003e` : A function that returns `AsyncIterator` you got from your `pubsub.asyncIterableIterator`.\n- `filterFn: (payload, variables, context, info) =\u003e boolean | Promise\u003cboolean\u003e` - A filter function, executed with the payload (the published value), variables, context and operation info, must return `boolean` or `Promise\u003cboolean\u003e` indicating if the payload should pass to the subscriber.\n\nFor 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:\n\n```js\nimport { withFilter } from \"graphql-subscriptions\";\n\nconst SOMETHING_CHANGED_TOPIC = \"something_changed\";\n\nexport const resolvers = {\n  Subscription: {\n    somethingChanged: {\n      subscribe: withFilter(\n        () =\u003e pubsub.asyncIterableIterator(SOMETHING_CHANGED_TOPIC),\n        (payload, variables) =\u003e {\n          return payload.somethingChanged.id === variables.relevantId;\n        }\n      ),\n    },\n  },\n};\n```\n\n\u003e Note that when using `withFilter`, you don't need to wrap your return value with a function.\n\n### Channels Mapping\n\nYou can map multiple channels into the same subscription, for example when there are multiple events that trigger the same subscription in the GraphQL engine.\n\n```js\nconst SOMETHING_UPDATED = \"something_updated\";\nconst SOMETHING_CREATED = \"something_created\";\nconst SOMETHING_REMOVED = \"something_removed\";\n\nexport const resolvers = {\n  Subscription: {\n    somethingChanged: {\n      subscribe: () =\u003e\n        pubsub.asyncIterableIterator([\n          SOMETHING_UPDATED,\n          SOMETHING_CREATED,\n          SOMETHING_REMOVED,\n        ]),\n    },\n  },\n};\n```\n\n### Payload Manipulation\n\nYou can also manipulate the published payload, by adding `resolve` methods to your subscription:\n\n```js\nconst SOMETHING_UPDATED = \"something_updated\";\n\nexport const resolvers = {\n  Subscription: {\n    somethingChanged: {\n      resolve: (payload, args, context, info) =\u003e {\n        // Manipulate and return the new value\n        return payload.somethingChanged;\n      },\n      subscribe: () =\u003e pubsub.asyncIterableIterator(SOMETHING_UPDATED),\n    },\n  },\n};\n```\n\nNote 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`.\n\n### Usage with callback listeners\n\nYour database might have callback-based listeners for changes, for example something like this:\n\n```js\nconst listenToNewMessages = (callback) =\u003e {\n  return db.table(\"messages\").listen((newMessage) =\u003e callback(newMessage));\n};\n\n// Kick off the listener\nlistenToNewMessages((message) =\u003e {\n  console.log(message);\n});\n```\n\nThe `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.\n\nWe recommend using the [`callback-to-async-iterator`](https://github.com/withspectrum/callback-to-async-iterator) module to convert your callback-based listener into an async iterator:\n\n```js\nimport asyncify from \"callback-to-async-iterator\";\n\nexport const resolvers = {\n  Subscription: {\n    somethingChanged: {\n      subscribe: () =\u003e asyncify(listenToNewMessages),\n    },\n  },\n};\n```\n\n### Custom `AsyncIterator` Wrappers\n\nThe value you should return from your `subscribe` resolver must be an `AsyncIterable`.\n\nYou can wrap an `AsyncIterator` with custom logic for your subscriptions. For compatibility with APIs that require `AsyncIterator` or `AsyncIterable`, your wrapper can return an `AsyncIterableIterator` to comply with both.\n\nFor example, the following implementation manipulates the payload by adding some static fields:\n\n```typescript\nexport const withStaticFields = (\n  asyncIterator: AsyncIterator\u003cany\u003e,\n  staticFields: Object\n): Function =\u003e {\n  return (\n    rootValue: any,\n    args: any,\n    context: any,\n    info: any\n  ): AsyncIterableIterator\u003cany\u003e =\u003e {\n    return {\n      next() {\n        return asyncIterator.next().then(({ value, done }) =\u003e {\n          return {\n            value: {\n              ...value,\n              ...staticFields,\n            },\n            done,\n          };\n        });\n      },\n      return() {\n        return Promise.resolve({ value: undefined, done: true });\n      },\n      throw(error) {\n        return Promise.reject(error);\n      },\n      [Symbol.asyncIterator]() {\n        return this;\n      },\n    };\n  };\n};\n```\n\n\u003e You can also take a look at `withFilter` for inspiration.\n\n### PubSub Implementations\n\nIt can be easily replaced with some other implementations of [PubSubEngine abstract class](https://github.com/apollographql/graphql-subscriptions/blob/master/src/pubsub-engine.ts). Here are a few of them:\n\n- Use Redis with https://github.com/davidyaha/graphql-redis-subscriptions\n- Use Google PubSub with https://github.com/axelspringer/graphql-google-pubsub\n- Use MQTT enabled broker with https://github.com/aerogear/graphql-mqtt-subscriptions\n- Use RabbitMQ with https://github.com/cdmbase/graphql-rabbitmq-subscriptions\n- Use AMQP (RabbitMQ) with https://github.com/Surnet/graphql-amqp-subscriptions\n- Use Kafka with https://github.com/ancashoria/graphql-kafka-subscriptions\n- Use Kafka (using [Kafkajs](https://www.npmjs.com/package/kafkajs)) with https://github.com/tomasAlabes/graphql-kafkajs-subscriptions\n- Use Postgres with https://github.com/GraphQLCollege/graphql-postgres-subscriptions\n- Use NATS with https://github.com/moonwalker/graphql-nats-subscriptions\n- Use Mongoose (MongoDB) with https://github.com/Nickolasmv/graphql-mongoose-subscriptions\n- Use multiple backends with https://github.com/jcoreio/graphql-multiplex-subscriptions\n- Use Ably for multi-protocol support with https://github.com/ably-labs/graphql-ably-pubsub\n- Use Google Firestore with https://github.com/m19c/graphql-firestore-subscriptions\n- Use Amazon's Simple Notification Service (SNS) and Simple Queue Service (SQS) with https://github.com/sagahead-io/graphql-snssqs-subscriptions\n- [Add your implementation...](https://github.com/apollographql/graphql-subscriptions/pull/new/master)\n\nYou 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`.\n\n#### SubscriptionManager **@deprecated**\n\n`SubscriptionManager` is the previous alternative for using `graphql-js` subscriptions directly, and it's now deprecated.\n\nIf you are looking for its API docs, refer to [a previous commit of the repository](https://github.com/apollographql/graphql-subscriptions/blob/5eaee92cd50060b3f3637f00c53960f51a07d0b2/README.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapollographql%2Fgraphql-subscriptions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapollographql%2Fgraphql-subscriptions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapollographql%2Fgraphql-subscriptions/lists"}