Skip to content
This repository was archived by the owner on Mar 20, 2023. It is now read-only.

Subscriptions support #390

Closed
mysterioushunt opened this issue Aug 30, 2017 · 52 comments
Closed

Subscriptions support #390

mysterioushunt opened this issue Aug 30, 2017 · 52 comments

Comments

@mysterioushunt
Copy link

Support GraphQL subscriptions or is there a way to use apollographql/graphql-subscriptions and apollographql/subscriptions-transport-ws with express-graphql?

@perrosnk
Copy link

+1

2 similar comments
@bwoodlt
Copy link

bwoodlt commented Nov 12, 2017

+1

@gauravmakkar
Copy link

+1

@junminstorage
Copy link
Contributor

subscriptions-transport-ws should create a websocket server. And I figured it out like below by adding subscription operation support in express-graphql's graphiql explorer.

const { execute, subscribe } = require('graphql');
const {createServer} = require('http');
const  { SubscriptionServer } = require('subscriptions-transport-ws');

const PORT = 4000;
const subscriptionsEndpoint = `ws://localhost:${PORT}/subscriptions`;

var app = express();
app.use('/graphql',  graphqlHTTP({
    schema: schema,
    graphiql: true,
    subscriptionsEndpoint: subscriptionsEndpoint
}));

// Create listener server by wrapping express app
const webServer = createServer(app);

webServer.listen(PORT, () => {
    console.log(`GraphQL is now running on http://localhost:${PORT}`);

    // Set up the WebSocket for handling GraphQL subscriptions.
    new SubscriptionServer({
        execute,
        subscribe,
        schema
    }, {
        server: webServer,
        path: '/subscriptions',
    });

});

Let me know if this solves the issue and I can create a PR.

@calvernaz
Copy link

@junminstorage this didn't work out for me. I had to plug the module graphql-playground-middleware-express to make it work, but I'm still investing what's the issue tho, given that I'm not sure if the problem is with GraphiQL not triggering the connection.

@junminstorage
Copy link
Contributor

@calvernaz thanks for bringing this up. conjunction with above I will need make a PR to expresss-graphql to make it work.
Let me create PR today.

@junminstorage
Copy link
Contributor

PR: #436
@calvernaz let me know if it works for you.

@calvernaz
Copy link

Sure @junminstorage, is the fix pinned to any specific version?

@junminstorage
Copy link
Contributor

I merged the current master to my PR branch. Actually it should work for last release as well which I tested. But if you can help me try it out with latest release and confirm, then we have good confidence to ask @IvanGoncharov to approve it.

@calvernaz
Copy link

calvernaz commented May 12, 2018

The last version still doesn't work, and it makes sense for me given that commit is not merged yet.

Maybe it worked for you because was cached or you missed to delete your local copy?

I tried to point my dependency to your repository but without success, not sure why npm refuses to pull the code from there.

@junminstorage
Copy link
Contributor

Right, the PR is not merged yet and not in any releases. I was meaning the changes in the PR should work for any release greater than v0.6.12 and master too.

For your local test, you need to remove the existing express-graphql in the node_modules/ folder under the nodejs project you are working on, then git clone https://github.com/junminstorage/express-graphql/ , and checkout branch named 'subscription-graphiql-support', then do npm link install this specific project, see doc here: https://docs.npmjs.com/cli/link

Let me know if you still have any problems after doing this.

I am planning to build a sample project here: https://github.com/junminstorage/graphql-sample, so you may be able to check it out and run it to see how it works. But it will take me some time to do it.

@calvernaz
Copy link

Good news, it worked!! I had to build the dependency first to create the dist folder where the package.json points to the main file, but worked as shown in the image
screen shot 2018-05-14 at 20 47 28

@junminstorage
Copy link
Contributor

Yep, the source code is typescript. And that is awesome! Thank you!

@IvanGoncharov can you comment on the PR #436 and so we can move forward on this?

@IvanGoncharov
Copy link
Member

@junminstorage I left a comment in #436 (comment).

@carlos-cne
Copy link

Hi! this PR was commited? I'm trying to do the same thing, but, doesn't worked here...

@carlos-cne
Copy link

Good news, it worked!! I had to build the dependency first to create the dist folder where the package.json points to the main file, but worked as shown in the image
screen shot 2018-05-14 at 20 47 28

Hi Calvernaz, can u show me how you builded the dependency at package.json?

@calvernaz
Copy link

Good news, it worked!! I had to build the dependency first to create the dist folder where the package.json points to the main file, but worked as shown in the image
screen shot 2018-05-14 at 20 47 28

Hi Calvernaz, can u show me how you builded the dependency at package.json?

Can you check if this works for you? https://github.com/calvernaz/express-graphql
I stop waiting for the change and creating a version with that fixed.

@junminstorage
Copy link
Contributor

just commented here to show my willing to work on this PR if anything we need for it to merge

@Lcmkey
Copy link

Lcmkey commented Dec 25, 2018

Good news, it worked!! I had to build the dependency first to create the dist folder where the package.json points to the main file, but worked as shown in the image
screen shot 2018-05-14 at 20 47 28

Hi Calvernaz, can u show me how you builded the dependency at package.json?

Can you check if this works for you? https://github.com/calvernaz/express-graphql
I stop waiting for the change and creating a version with that fixed.

hello, @calvernaz .
can you provide any project sample code for me to reference?
I have study how to subscribe function with "express-graphql" package a few days, but unfortunately.... fail again and again and again......... until now........fail,
Thanks~~~

@junminstorage
Copy link
Contributor

junminstorage commented Dec 26, 2018

@Lcmkey, besides you need the code changes like in PR #436 to express-graphql, rebuild the dist/ folder inside, Or point (npm link) your local express-graphql to https://github.com/calvernaz/express-graphql, do you also have the code snippet like below in your server side?

#390 (comment)

@Lcmkey
Copy link

Lcmkey commented Dec 28, 2018

@junminstorage
Thanks for reply. My server side setting exactly like #390 (comment) and the request method that is websocket. Also, when i made a request to server, it return "[object Object]" instead of listening word "Your subscription data will appear here after server publication!".
I have updated a simple coding on my github( https://github.com/Lcmkey/draft ), can you please help for find out the problem or give me some suggestion, thanks.

@martinlevesque
Copy link

martinlevesque commented Oct 9, 2019

Is there a complete example somewhere ? I have been trying to make subscriptions work with express-graphql and subscriptions-transport-ws with no success.

See below the src, if you see any issue let me know. The subscribe function is never triggered, the client can be run in command line (no browser).

My server:

const express = require('express')
const { createServer } = require('http')
const graphqlHTTP = require('express-graphql')
const { buildSchema, execute, subscribe } = require('graphql')
const  { SubscriptionServer } = require('subscriptions-transport-ws')
const { PubSub } = require('graphql-subscriptions')

const PORT = 4000

const subscriptionsEndpoint = `ws://localhost:${PORT}/subscriptions`;
const pubsub = new PubSub();

// merging schemas:
// https://stackoverflow.com/questions/45911002/can-two-graphqlschema-instances-be-merged

// Construct a schema, using GraphQL schema language
var schema = buildSchema(`

  type MyDocument {
    id: String
    title: String
  }

  type Query {
    retrieveDocument: MyDocument
  }

  type Subscription {
    newDocument: MyDocument
  }
`);

// The root provides a resolver function for each API endpoint
const root = {

  retrieveDocument: () => {

    console.log(`hello`)
    pubsub.publish('NOTIFICATION_NEW_DOCUMENT', { newDocument: {id: "222", title: 'newdocument2' }});

    return {
      id: '111',
      title: 'hello world'
    }
  },

  //Subscription: {
    newDocument: {

      resolve: (arguments) => {
        console.log(`resolving new document`)
        return { 
          id: '112233'
        };
      },


      subscribe: () => {
        console.log(`subscribed...`)
        return pubsub.asyncIterator('NOTIFICATION_NEW_DOCUMENT')
      }
      //  return 
      //}
    }
  //}
  
};

const app = express();

app.use(
  '/graphql',
  graphqlHTTP({
    schema: schema,
    rootValue: root,
    graphiql: true,
    subscriptionsEndpoint
  }),
);

const webServer = createServer(app);

app.listen(PORT, () => {

  // Subscriptions handling:
  new SubscriptionServer({
      execute,
      subscribe,
      schema
  }, {
      server: webServer,
      path: '/subscriptions',
  });

  console.log(`Running a GraphQL API server at http://localhost:${PORT}/graphql`);
});

Client:


const { SubscriptionClient } = require('subscriptions-transport-ws')
const fetch = require('node-fetch')
const gql = require('graphql-tag')

const { ApolloClient } = require('apollo-client')

const { InMemoryCache } = require('apollo-cache-inmemory')
const { createHttpLink } = require('apollo-link-http');

const ws = require('ws')

const client = new SubscriptionClient('ws://localhost:4000/subscriptions', {
  reconnect: true,
}, ws);

const apolloClient = new ApolloClient({
  link: createHttpLink({ uri: 'http://localhost:4000/graphql', fetch }),
  cache: new InMemoryCache(),
  networkInterface: client,
});

apolloClient.subscribe({
  query: gql`
    subscription newDocumentEventHere {
      newDocument {
        id
      }
    }`,
  variables: {}
}).subscribe({
  next (data) {
    // Notify your application with the new arrived data
    console.log(`oh new data...${JSON.stringify(data)}`)
  }
});

setTimeout(() => {
  apolloClient.query({
    query: gql`
      {
        retrieveDocument {
          id
        }
      }
    `
  }).then((result) => console.log(`res2 ${JSON.stringify(result)}`))
}, 1000)

package.json:

{
  "name": "subscription-express-graphql",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node server.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "apollo-cache-inmemory": "^1.6.3",
    "apollo-client": "^2.6.4",
    "apollo-link-http": "^1.5.16",
    "express": "^4.17.1",
    "express-graphql": "^0.9.0",
    "graphql": "^14.5.8",
    "graphql-subscriptions": "^1.1.0",
    "graphql-tag": "^2.10.1",
    "node-fetch": "^2.6.0",
    "nodemon": "^1.19.3",
    "subscriptions-transport-ws": "^0.9.16"
  }
}

@calvinlarano97
Copy link

Is there a complete example somewhere ? I have been trying to make subscriptions work with express-graphql and subscriptions-transport-ws with no success.

See below the src, if you see any issue let me know. The subscribe function is never triggered, the client can be run in command line (no browser).

My server:

const express = require('express')
const { createServer } = require('http')
const graphqlHTTP = require('express-graphql')
const { buildSchema, execute, subscribe } = require('graphql')
const  { SubscriptionServer } = require('subscriptions-transport-ws')
const { PubSub } = require('graphql-subscriptions')

const PORT = 4000

const subscriptionsEndpoint = `ws://localhost:${PORT}/subscriptions`;
const pubsub = new PubSub();

// merging schemas:
// https://stackoverflow.com/questions/45911002/can-two-graphqlschema-instances-be-merged

// Construct a schema, using GraphQL schema language
var schema = buildSchema(`

  type MyDocument {
    id: String
    title: String
  }

  type Query {
    retrieveDocument: MyDocument
  }

  type Subscription {
    newDocument: MyDocument
  }
`);

// The root provides a resolver function for each API endpoint
const root = {

  retrieveDocument: () => {

    console.log(`hello`)
    pubsub.publish('NOTIFICATION_NEW_DOCUMENT', { newDocument: {id: "222", title: 'newdocument2' }});

    return {
      id: '111',
      title: 'hello world'
    }
  },

  //Subscription: {
    newDocument: {

      resolve: (arguments) => {
        console.log(`resolving new document`)
        return { 
          id: '112233'
        };
      },


      subscribe: () => {
        console.log(`subscribed...`)
        return pubsub.asyncIterator('NOTIFICATION_NEW_DOCUMENT')
      }
      //  return 
      //}
    }
  //}
  
};

const app = express();

app.use(
  '/graphql',
  graphqlHTTP({
    schema: schema,
    rootValue: root,
    graphiql: true,
    subscriptionsEndpoint
  }),
);

const webServer = createServer(app);

app.listen(PORT, () => {

  // Subscriptions handling:
  new SubscriptionServer({
      execute,
      subscribe,
      schema
  }, {
      server: webServer,
      path: '/subscriptions',
  });

  console.log(`Running a GraphQL API server at http://localhost:${PORT}/graphql`);
});

Client:


const { SubscriptionClient } = require('subscriptions-transport-ws')
const fetch = require('node-fetch')
const gql = require('graphql-tag')

const { ApolloClient } = require('apollo-client')

const { InMemoryCache } = require('apollo-cache-inmemory')
const { createHttpLink } = require('apollo-link-http');

const ws = require('ws')

const client = new SubscriptionClient('ws://localhost:4000/subscriptions', {
  reconnect: true,
}, ws);

const apolloClient = new ApolloClient({
  link: createHttpLink({ uri: 'http://localhost:4000/graphql', fetch }),
  cache: new InMemoryCache(),
  networkInterface: client,
});

apolloClient.subscribe({
  query: gql`
    subscription newDocumentEventHere {
      newDocument {
        id
      }
    }`,
  variables: {}
}).subscribe({
  next (data) {
    // Notify your application with the new arrived data
    console.log(`oh new data...${JSON.stringify(data)}`)
  }
});

setTimeout(() => {
  apolloClient.query({
    query: gql`
      {
        retrieveDocument {
          id
        }
      }
    `
  }).then((result) => console.log(`res2 ${JSON.stringify(result)}`))
}, 1000)

package.json:

{
  "name": "subscription-express-graphql",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node server.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "apollo-cache-inmemory": "^1.6.3",
    "apollo-client": "^2.6.4",
    "apollo-link-http": "^1.5.16",
    "express": "^4.17.1",
    "express-graphql": "^0.9.0",
    "graphql": "^14.5.8",
    "graphql-subscriptions": "^1.1.0",
    "graphql-tag": "^2.10.1",
    "node-fetch": "^2.6.0",
    "nodemon": "^1.19.3",
    "subscriptions-transport-ws": "^0.9.16"
  }
}

same problem. anyone here could help us.

@tylerreckart
Copy link

tylerreckart commented Oct 12, 2019

@calvinlarano97, @martinlevesque There is currently no support for subscriptions in this package. I integrated this PR into my own package for use in my course on GraphQL, but it should be noted that it was for demonstration purposes only. https://github.com/graphql-in-motion/express-graphql
It is being used here: https://github.com/graphql-in-motion/graphql-news/blob/master/src/server/index.js

I have been following this issue for at this point a few years, and I wouldn't get your hopes up that the maintainers will do anything about it anytime soon. The best option is likely to find another package to build your server.

@raitucarp
Copy link

Is this project even still maintained?

@junminstorage
Copy link
Contributor

junminstorage commented Oct 24, 2019

currently apollo graphql is the most popular platform for anyone who wants to adopt graphql in production, lacking support from the facebook for this project, making my PR #436 sitting there for long time.

@junminstorage
Copy link
Contributor

@IvanGoncharov got your point. Now winter is coming along with holidays, and now I am thinking about raising my sleeves to write my own and replace the subscription client.

@raitucarp
Copy link

Why I bump this feature request? Honestly, I need dynamically reload schema with a subscription feature, express-graphql is easy enough for doing dynamic schema loader.

@IvanGoncharov
Copy link
Member

@martijnwalraven So it seems that the current consensus from GraphQL Foundation is to try to provide some kind of hook/callback that allows you to use different transports for subscriptions including WS transport from Apollo.
It would be great if someone volunteers to experiment with that so we will see if it possible and how much complexity it will add?

@tylerreckart
Copy link

@IvanGoncharov That's something I can look into.

@junminstorage
Copy link
Contributor

@IvanGoncharov can you elaborate on this? as all of the sample code people provided above, for the express backend to support the subscription, it is up to application developer to hook up any SubscriptionServer into express and work with this express-graphql middleware.

the PR is mainly to pass ws endpoint to front-end, https://github.com/graphql/express-graphql/pull/436/files#diff-1fdf421c05c1140f6d71444ea2b27638R207, the moot point or the only place third part library introduced to demonstrate the subscription capability on the UI is when it is rendered during the development phrase ONLY

@martinlevesque
Copy link

martinlevesque commented Nov 7, 2019

If I understand correctly (I might be wrong - noob here) the issue previously noted by @IvanGoncharov is with the package subscriptions-transport-ws being added in src/renderGraphiQL.js, not the change in src/index.js (?).

Perhaps we could add the src/index.js change first to allow people to actually make it work - without subscription support in graphiql and with proper warning ?

@junminstorage
Copy link
Contributor

nope, see #390 (comment) for example. and please check out the PR linked to this issue.

@nileio
Copy link

nileio commented Apr 7, 2020

looks like this thread is dead .. its April 2020, and looks like its still stagnant for some reason though the change look pretty small.. anyone ?

@martinlevesque
Copy link

martinlevesque commented Apr 8, 2020

Yeah it's kind of disappointing. I would suggest adding a clear comment in the readme stating that there is no support for subscriptions, and no plan to add its support, and close this ticket.

@amjedomar
Copy link

The community (including me) desperately needs subscriptions feature in express-graphql

@acao
Copy link
Member

acao commented May 14, 2020

hey folks! i happen to be a maintainer. happy to see what i can do.

ivan has been busy with graphql and i’ve been busy with maintaining graphiql , graphql playground and the LSP.

sadly this repo has been neglected far more than it should be. if anyone is interested in becoming a maintainer of this repo that would be fantastic. it is widely used still by some very large companies

for now, is it ok if i close this issue and update the docs to note that this does not support subscriptions currently in the readme, and offer some links to alternatives that do?

@acao
Copy link
Member

acao commented May 14, 2020

also if someone wants to open a pull request for this feature, i would be happy to review it! ill try to keep a closer eye out in my github notifications

@abhijeetsingh-22
Copy link

If anyone is still looking for a solution to use subscriptions in express-graphql, I have found a simple way to do this. Have a look at this
https://youtu.be/r5KY5m5OXsI

@martinlevesque
Copy link

martinlevesque commented Jul 24, 2020

Hey @abhijeetsingh-22 thx will look into it. Would you mind to make a repo/gist with your sample app?

Edit: nevermind just saw the repo is here https://github.com/abhijeetsingh-22/Realtime-Chat-App

@abhijeetsingh-22
Copy link

abhijeetsingh-22 commented Jul 24, 2020

Hey @abhijeetsingh-22 thx will look into it. Would you mind to make a repo/gist with your sample app?

Its a pleasure If I could help
The video description has the link to repo.
Ping me if you have any query

@martinlevesque
Copy link

martinlevesque commented Jul 29, 2020

@abhijeetsingh-22 looked at your example. It works, however you basically have, if I understand correctly, two schemas, one with express-graphql and one on another http server with subscriptionserver, and the types basically need to be duplicated in both schemas. Is there a way to share types between two schemas (made an issue here abhijeetsingh-22/Realtime-Chat-App#1 ), where one use "ObjectType" and another use graphql-tags? If not it's not so much maintainable from my opinion, and not so clean, as typically you subscribe to the same types you query/mutate.

@abhijeetsingh-22
Copy link

@martinlevesque sure I will look into this issue. Currently I am little busy. I will update in 2-3 days

@martinlevesque
Copy link

martinlevesque commented Jul 30, 2020

works well with these 2 changes abhijeetsingh-22/Realtime-Chat-App#2 and abhijeetsingh-22/Realtime-Chat-App#1

Will have to check if it works with graphiql (I guess not?).
After checking this I would suggest to point a link to this sample (or include the sample example in "examples"), as it allows to have working subscriptions with express-graphql.

Edit: The documentation of subscription works in graphiql also with this example. However it does not work to make it work live with streaming messages in graphiql. To me that's fine - might not be depending on your use case thus.

@junminstorage
Copy link
Contributor

The PR for this is created #687. It contains a link to tutorial project showing how it is done for subscription and web socket integration.

@hongbo-miao
Copy link

hongbo-miao commented Oct 10, 2020

graphql-ws is another good library to provide GraphQL subscription (by far, the simplest and lightest one I found).

@joshbedo
Copy link

joshbedo commented Jan 3, 2021

Whats the status on this? Would love to be able to use subscriptions for a messaging feature I have.

@acao
Copy link
Member

acao commented Jan 3, 2021

oops forgot to close this ticket! juggling so many efforts in my free time 🥵 . it's very important to note that express-graphql has always supported subscriptions, it's just a matter of configuration. for example, graphql-ws has had a config example for some time.

we have started with updating the docs to show how to add subscriptions support using graphql-transport-ws.

also in @#687 we updated graphiql to work with subscriptions, but just with graphql-transport-ws for now.

we will follow up with a PR and documentation on how to add graphql-ws, which implements the transport specification that will replace graphql-transport-ws, as graphql-transport-ws is being retired as you can probably see in the project readme. to note, we are working with maintainers of both of these projects already.

And for now, I will close this ticket since we have documented this!

If anyone wants to see additional features added to improve the subscriptions documentation or have any other issues, feel free to open a new one! Happy subscribing graphql-ers!

@acao acao closed this as completed Jan 3, 2021
@joshbedo
Copy link

joshbedo commented Jan 5, 2021

Yeah more documentation would be great! its not super clear on how the setup works.

daemon1024 added a commit to osdc/ct-api that referenced this issue Feb 1, 2021
-   Publish a event when a new event is added ( mutation is triggered )
-   Clients can connect to /subscriptions using websocket connection
-   migrated to apollo-server-express due to lack of subscription support in express-graphql graphql/express-graphql#390
-   Update dependencies
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests