apollographql / graphql-subscriptions

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

Way to use this without subscriptions-transport-ws? #219

Open pranaypratyush opened 4 years ago

pranaypratyush commented 4 years ago

The package subscriptions-transport-ws seems to be really buggy. Is there a way to use this without that package?

boredland commented 4 years ago

I want to add to this and ask: Is there even any other transport for subscriptions?

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

I could imagine a transport using Firebase Cloud Messaging or even gRPC could be a viable alternative over websockets, but I don't find anybody doing anything other than subscriptions-transport-ws

n1ru4l commented 4 years ago

You can implement your own protocol. I implemented my own on top of socket.io for a project that was already using it.

boredland commented 4 years ago

You didn't, by any chance, release that somehow? I'm really a bit afraid adding such a thing as a user-brew.

n1ru4l commented 4 years ago

check-out: https://github.com/dungeon-revealer/dungeon-revealer/blob/c3b257cd0ec95a8f05f884fb24d88d1a105b36d1/server/routes/graphql.ts#L13 (backend)

and https://github.com/dungeon-revealer/dungeon-revealer/blob/c3b257cd0ec95a8f05f884fb24d88d1a105b36d1/src/relay-environment.ts#L15-L77 (frontend)

no guarantees I just hacked this together yesterday, still need to do some more testing and understanding how to terminate AsyncIterators

hongbo-miao commented 3 years ago

Check this https://github.com/enisdenjo/graphql-transport-ws I posted solution at https://stackoverflow.com/a/63939934/2000548

Copy here:

Server (GraphQL.js GraphQLSchema object way)

import { execute, subscribe, GraphQLObjectType, GraphQLSchema, GraphQLString } from 'graphql';
import { createServer } from 'graphql-transport-ws';
import { PubSub } from 'graphql-subscriptions';

const pubsub = new PubSub();

const subscription = new GraphQLObjectType({
  name: 'Subscription',
  fields: {
    greeting: {
      type: GraphQLString,
      resolve: (source) => {
        if (source instanceof Error) {
          throw source;
        }
        return source.greeting;
      },
      subscribe: () => {
        return pubsub.asyncIterator('greeting');
      },
    },
  },
});

const schema = new GraphQLSchema({
  query,
  subscription,
});

setInterval(() => {
  pubsub.publish('greeting', {
    greeting: 'Bonjour',
  });
}, 1000);

createServer(
  {
    schema,
    execute,
    subscribe,
  },
  {
    server,
    path: '/graphql',
  }
);

Server (GraphQL Schema Definition Language)

import { createServer } from 'graphql-transport-ws';
import { buildSchema } from 'graphql';

const schema = buildSchema(`
  type Subscription {
    greeting: String
  }
`);

const roots = {
  subscription: {
    greeting: async function* sayHiIn5Languages() {
      for (const hi of ['Hi', 'Bonjour', 'Hola', 'Ciao', 'Zdravo']) {
        yield { greeting: hi };
      }
    },
  },
};

createServer(
  {
    schema,
    execute,
    subscribe,
    roots,
  },
  {
    server, // Your HTTP server
    path: '/graphql',
  }
);

Client

const client = createClient({
  url: 'wss://localhost:5000/graphql',
});

client.subscribe(
  {
    query: 'subscription { greeting }',
  },
  {
    next: (data) => {
      console.log('data', data);
    },
    error: (error) => {
      console.error('error', error);
    },
    complete: () => {
      console.log('no more greetings');
    },
  }
);