graphql-firebase-subscriptions
TypeScript icon, indicating that this package has built-in type declarations

2.5.0 • Public • Published

GraphQL Subscriptions through Firebase Realtime Database

JavaScript Style Guide QA Publish to NPM and GCR codecov

This is a GraphQL Subscriptions implementation that uses Firebase Realtime Database as a message broker.

Comparison

Depending on your use-case this may or may not be the tool for you, this implementation is not meant as a way to listen to state updates on persisted data, for that you should probably look at graphql-firestore-subscriptions. This implementation is closer to an alternative to Google PubSub. Now you may wonder, "why not use PuSub then?" well, basically I had concerns that the PubSub documentation stated the performance on low message volumes might not be great on PubSub since the priority was low latency at high load, some graphs I saw showed seconds of latency for the types of volumes I was looking at, whereas I've experienced a more consistent performance from RTDB, but it doesn't go lower with scale like PubSub does. For using PubSub, there's graphql-google-pubsub.

Now Firebase RTDB isn't without latency, not at all! And to alleviate this, this library also provides an optional "local cache", this is really useful if you're running on something like Google Cloud Run where you have multiple instances serving requests. Turning this on will make the library work on an "at-least-once" delivery principle. If something happens (most likely a mutation) on the same instance a subscriber is connected to it will use an internal in-memory EventEmitter and "instantly" forward the message. It will also publish the message to Firestore RTDB and keep the node ID in a short-lived local cache, when the message later arrives, and assuming its ID hasn't expired from the cache, it will simply be ignored and not re-emitted to subscribers connected to the instance that originally received the message.

Usage

By default, the ref /graphql-firebase-subscriptions in your database will be used as the root for messages.

import { PubSub } from 'graphql-firebase-subscriptions'

enum Topic {
  NEW_COMMENT = 'new-comment'
}

const pubSub = new PubSub()

const Resolvers = {
  Subscription: {
    newComment: {
      subscribe: () => pubSub.asyncIterator(Topic.NEW_COMMENT)
    }
  },
  Mutation: {
    async addComment (_, args, ctx) {
      const comment = await ctx.dataSources.comments.createOne(args.postId, args.comment)
      await pubSub.publish(Topic.NEW_COMMENT, { postId: args.postId, commentId: comment.id })

      return comment
    }
  }
}

Local Cache

Enabling the local cache for speed up is as simple as a boolean

import { PubSub } from 'graphql-firebase-subscriptions'

const pubSub = new PubSub({ localCache: true })

Only New

This flag allows receiving only messages which were published after client subscription to some topic. Default behaviour is to receive all messages which were published and not deleted (see Cleanup section).

import { PubSub } from 'graphql-firebase-subscriptions'

const pubSub = new PubSub({ onlyNew: true })

When creating an asyncIterator you can override this option

import { PubSub } from 'graphql-firebase-subscriptions'

const pubSub = new PubSub({ onlyNew: false })

const iterator = pubSub.asyncIterator(['TOPIC'], { onlyNew: true })

Alternative base ref

You can use an alternative base ref for the message brokerage, useful if you want separate instances with the same topics.

import { PubSub } from 'graphql-firebase-subscriptions'
import { getDatabase } from 'firebase-admin/database'

const pubSub = new PubSub({
  ref: getDatabase().ref('/path/to/base/ref')
})

Cleanup

This library requires you to clean up old messages, else it will just keep adding messages to the topics forever. This could slow down message delivery, and it'll waste storage and cost.

To help with this task, the library provides a Firebase Function that works on a Google Cloud Scheduler Trigger. Note that per Firebase's own documentation a cloud scheduler job costs about USD 0.10 per month and requires you to be on the Blaze plan for firebase.

To use it, just generate a handler and re-export it

import getDeletionRoutineFunction from 'graphql-firebase-subscriptions/firebase-functions'

enum Topics {
  NEW_COMMENT = 'new-comment'
}

export const pubSubDeletionRoutine = getDeletionRoutineFunction({
  topics: Topics,

  // -------OPTIONAL-------
  // You can overwrite the base ref, if you've done so when using the PubSub
  ref: getDatabase.ref('/graphql-firebase-subscriptions'),
  // you can override the schedule for the function, by default it runs every
  // 10 minutes
  schedule: 'every 10 minutes',
  // and you can override the maximum time a message should be stored,
  // the default is to delete messages older than 10 minutes
  maxAge: 600_000
})

Readme

Keywords

Package Sidebar

Install

npm i graphql-firebase-subscriptions

Weekly Downloads

23

Version

2.5.0

License

MIT

Unpacked Size

27.6 kB

Total Files

18

Last publish

Collaborators

  • swantzter