apollographql / graphql-subscriptions

:newspaper: A small module that implements GraphQL subscriptions for Node.js
MIT License
1.58k stars 133 forks source link

Transfer maintenance and resurrect graphql-subscriptions #240

Open Urigo opened 3 years ago

Urigo commented 3 years ago

We at The Guild finally got again a production use case to use this library and we saw that the library was unmaintained for a couple of years.

So we would love to resurrect the library and bring it up to speed.

Will the kind people at Apollo be open to transfer the maintenance of that package to The Guild to give it and the community of users and other pubs integration authors a new life?

It might save the community from the hassle of moving to another package like what happened with the subscriptions-transport-ws library

(a lot of the original code was written by @dotansimha and myself so I'm sure it will stay in good hands)

Thank you

@grantwwu @hwillson

grantwwu commented 3 years ago

I don't really have any ability to transfer ownership - I merely got commit bits, I can't even cut a release myself - but +1 to someone maintaining this.

valdestron commented 3 years ago

Please do, what happened to Apollo? The same is happening with other libs ans servers like federation.

n1ru4l commented 3 years ago

BTW this package can be completely replaced with the Node.js events.EventEmitter nowadays.

See https://nodejs.org/api/events.html#events_events_on_emitter_eventname_options

import * as events from "events";
import { GraphQLBoolean } from "graphql";
import {
  GraphQLObjectType,
  GraphQLString,
  GraphQLSchema,
  subscribe,
  parse
} from "graphql";

const emitter = new events.EventEmitter();

const Subscription = new GraphQLObjectType({
  name: "Subscription",
  fields: {
    test: {
      type: GraphQLString,
      resolve: value => value,
      subscribe: async function*() {
        const source = events.on(emitter, "foo");
        for await (const [value] of source) {
          yield value;
        }
      }
    }
  }
});

const schema = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: "Query",
    fields: { _: { type: GraphQLBoolean } }
  }),
  subscription: Subscription
});

subscribe({
  schema,
  document: parse(/* GraphQL */ `
    subscription {
      test
    }
  `)
}).then(async asyncIterator => {
  process.nextTick(() => {
    emitter.emit("foo", "bar");
  });
  for await (const value of asyncIterator) {
    console.log(value);
    asyncIterator?.();
  }
});

The only benefit I see in further maintaining this package is for non-Node.js environments that don't have a similar solution or as a common interface for distributed message systems that work over redis, etc. But, in that use case, you could also use an abstraction over EventEmitter instead (e.g. https://www.npmjs.com/package/merkury for Redis).

Filtering/mapping can also be done easily by composing generator functions:

async-iterator.ts

export const map = <T, O>(map: (input: T) => Promise<O> | O) =>
  async function* mapGenerator(asyncIterable: AsyncIterableIterator<T>) {
    for await (const value of asyncIterable) {
      yield map(value);
    }
  };

export const filter = <T, U extends T = T>(filter: (input: T) => input is U) =>
  async function* filterGenerator(asyncIterable: AsyncIterableIterator<T>) {
    for await (const value of asyncIterable) {
      if (filter(value)) {
        yield value;
      }
    }
  };
const first = (arr) => arr[0]
const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x);

const Subscription = new GraphQLObjectType({
  name: "Subscription",
  fields: {
    test: {
      type: GraphQLString,
      subscribe: () =>
        pipe(
          events.on(emitter, "foo"),
          map(first),
          map(value => value.repeat(3)),
          filter(value => value.length < 10)
        )
    }
  }
});
Urigo commented 2 years ago

@glasser any chance to reconsider this?

alfaproject commented 1 year ago

@Urigo did you guys ended doing something else or still using this library?

Urigo commented 1 year ago

@alfaproject we've moved to Yoga Server and added built in, out of the box support for Subscriptions and all the features that this library provides.

Also about transports we actively maintain the graphql-ws, graphql-sse and graphql-http libraries.

But for the people who don't want to migrate, internally in Yoga we have createPubSub which is kinda similar to what the this original package was doing, but a more modern implementation which uses iterators and Typescript by default, which you can use in the same way.

You can find examples of using it here:

import { createPubSub } from 'graphql-yoga';

const pubSub = createPubSub()

// publish
pubSub.publish('newPost', newPost)

// subscribe 
(async () => {
  for await (const newPost of pubSub.subscribe('newPost')) {
    // event
  }
})()

and the docs for a full-blown GraphQL Subscriptions example.

The idea here is to use EventTarget interface to create a PubSub instead of creating a PubSub interface: https://github.com/dotansimha/graphql-yoga/blob/main/packages/subscription/src/create-pub-sub.ts

Let us know if that helps

alfaproject commented 1 year ago

We had to build our own web socket lambda function because there isn't one available for AWS API Gateway web sockets (or any implementation for serverless web sockets for that matter) and that's one of the reasons of using this library but for sure we can also extract exactly what we need

If you guys have an implementation of a server or server blocks that we can use to build our own implementation of Yoga on top of Lambda I'm all ears. I feel like we are always fighting with the existing ecosystem and status quo because everyone assumes that everyone else has a long running node server so the past 4 years of going 100% serverless have been painful for our GraphQL journey ):

enisdenjo commented 1 year ago

Hey hey, there's been a discussion a while back on graphql-ws about the AWS lambda support.

There are currently two options for serverless WS on AWS (that I know of):

Hope the libraries, and the respected maintainers, can ease up your process and provide help.

Aeolun commented 1 year ago

For those not interested in switching to a whole different server to fix a minor issue, I've published a fork here: https://github.com/Aeolun/graphql-subscriptions-continued that basically just releases the release-3.0 branch in this repository.

It doesn't update the dependent packages (e.g. graphql-redis-subscriptions), but if they feel like it they can switch.