Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using subscriptions with express on the same port #1902

Closed
ksrb opened this issue Oct 31, 2018 · 8 comments
Closed

Using subscriptions with express on the same port #1902

ksrb opened this issue Oct 31, 2018 · 8 comments
Labels
📝 documentation Focuses on changes to the documentation (docs)

Comments

@ksrb
Copy link

ksrb commented Oct 31, 2018

The current docs have a example on how to do this here of importance there is a note that says:

// ⚠️ Pay attention to the fact that we are calling `listen` on the http server variable, and not on `app`.
httpServer.listen(PORT, () => {
  console.log(`🚀 Server ready at http://localhost:${PORT}${server.graphqlPath}`)
  console.log(`🚀 Subscriptions ready at ws://localhost:${PORT}${server.subscriptionsPath}`)
})

Unfortunately using the httpServer to listen on a port disables all the express routing on that port.

I've been getting around this by doing something like:

httpServer.listen(PORT, () => {
  console.log(`🚀 Server ready at http://localhost:${PORT}${server.graphqlPath}`)
  console.log(`🚀 Subscriptions ready at ws://localhost:${PORT}${server.subscriptionsPath}`)
})

app.listen(differentPort, () => console.log(`listening on http://localhost:${port}`));

But this isn't really ideal, is there a way to get the subscriptions and the express application to work on the same port?

Additional Information

I found what appears to be older documentation setting up the apollo-server to do this exact thing:

import express from 'express';
import bodyParser from 'body-parser';
import { graphqlExpress } from 'apollo-server-express';
import { createServer } from 'http';
import { execute, subscribe } from 'graphql';
import { PubSub } from 'graphql-subscriptions';
import { SubscriptionServer } from 'subscriptions-transport-ws';
import { myGraphQLSchema } from './my-schema';

const PORT = 3000;
const app = express();

app.use('/graphql', bodyParser.json(), graphqlExpress({ schema: myGraphQLSchema }));

const pubsub = new PubSub();
const server = createServer(app);

server.listen(PORT, () => {
    new SubscriptionServer({
      execute,
      subscribe,
      schema: myGraphQLSchema,
    }, {
      server: server,
      path: '/subscriptions',
    });
});

However, the apollo-server-express package no longer exports a graphqlExpress module and instead only has ApolloServer, ServerRegistration, registerServer. So far I've only used ApolloServer with installSubscriptionHandlers to setup basic subscriptions and haven't looked at the other methods. Is there a way to setup subscriptions on the same port as the express application or am I just chasing a dead end?

@sbrichardson
Copy link
Contributor

sbrichardson commented Dec 1, 2018

Here's some working code, minus some custom details. I'm also using a customized ApolloServer class with changes to applyMiddleware, but it's not related to your issue. I noticed you need to get the order and pass the server instances in a specific way, or you get an error. I also moved some of methods from inside applyMiddleware (apollo upload/cors etc), just fyi.

  /* Request middleware */
  const middleware = [
    session(sessionConfig),
    cors(CORS_CONFIG),
    compression(COMPRESSION_CONFIG),
    json(),
    apolloUploadExpress(UPLOAD_OPTS),
    auth,
    getSchema,
  ]

  /* Instantiate app server, add request middleware */
  const app = express().use(GQL_SERVER_ENDPOINT, middleware)

  /* Instantiate GraphQL server */
  const server = new CustomApolloServer({
    /* GraphQL minimal public schema */
    schema: makeExecutableSchema(publicSchema),
    /* Apollo GraphQL datasources */
    dataSources: getDataSources,
    /* GraphQL context method, subscriptions */
    context: getContext,
    /* GraphQL subscriptions connection handlers */
    subscriptions: {
      onConnect: subConnect,
      onDisconnect: subDisconnect,
    },
  })

  /* Apollo GraphQL Server specific middleware */
  server.applyMiddleware({ app, path: GQL_SERVER_ENDPOINT })

  /* Create GraphQL subscriptions server */
  const httpServer = http.createServer(app)

  /* Attach subscription server to GraphQL server */
  server.installSubscriptionHandlers(httpServer)

  /* Start server */
  httpServer.listen(PORT, () => {
    console.log(`http://localhost:${PORT}${server.graphqlPath}`)
    console.log(`ws://localhost:${PORT}${server.subscriptionsPath}`)
  })

If you need to make more advanced changes, you would need to customize applyMiddleware and the code the instantiates the subscription server. You can find graphqlExpress exported at the below path, but It's a bit more complicated in 2.0. I noticed the order, and how the servers are passed in the above code is important. Does this help?

import { graphqlExpress } from 'apollo-server-express/dist/expressApollo'

@gforge
Copy link

gforge commented Dec 2, 2018

As part of debugging a similar issue I wrote a minimal Express + Apollo server app with subscriptions, you can find it here: https://github.com/gforge/subscription_example It seems to work with shared port. Hope it helps!

@Elfayer
Copy link

Elfayer commented Feb 21, 2019

Solution here: https://www.apollographql.com/docs/apollo-server/features/subscriptions.html#middleware

const http = require('http');
const { ApolloServer } = require('apollo-server-express');
const express = require('express');

const PORT = 4000;
const app = express();
const server = new ApolloServer({ typeDefs, resolvers });

server.applyMiddleware({app})

const httpServer = http.createServer(app);
server.installSubscriptionHandlers(httpServer);

// ⚠️ Pay attention to the fact that we are calling `listen` on the http server variable, and not on `app`.
httpServer.listen(PORT, () => {
  console.log(`🚀 Server ready at http://localhost:${PORT}${server.graphqlPath}`)
  console.log(`🚀 Subscriptions ready at ws://localhost:${PORT}${server.subscriptionsPath}`)
})

@B3none
Copy link

B3none commented Dec 5, 2019

Solution here: https://www.apollographql.com/docs/apollo-server/features/subscriptions.html#middleware

const http = require('http');
const { ApolloServer } = require('apollo-server-express');
const express = require('express');

const PORT = 4000;
const app = express();
const server = new ApolloServer({ typeDefs, resolvers });

server.applyMiddleware({app})

const httpServer = http.createServer(app);
server.installSubscriptionHandlers(httpServer);

// ⚠️ Pay attention to the fact that we are calling `listen` on the http server variable, and not on `app`.
httpServer.listen(PORT, () => {
  console.log(`🚀 Server ready at http://localhost:${PORT}${server.graphqlPath}`)
  console.log(`🚀 Subscriptions ready at ws://localhost:${PORT}${server.subscriptionsPath}`)
})

Worked a treat! Thanks!

@khirod-dev
Copy link

@B3none i tried the above as i am recently looking to subscription. No luck i have been stuck with this . server runs fine. but the subscribe method is never called.
Posted the query in stackoverflow also no answer yet .

https://stackoverflow.com/questions/62835253/apollo-server-subscription-subscribe-method-is-never-called

@adri1wald
Copy link

having similar issues as @khirodAsurion. Everything seems to be working fine except for the subscribe function on the resolver for my subscription is not running. I logged in resolve function to verify this. Logging in the onConnect function suggests that client is successfully connecting over websocket. try catch block around pubsub.publish suggests it is not throwing an error. Result of await pubsub.publish is undefined. I have a single PubSub instance. Any ideas? :/

@niraj-khatiwada
Copy link

I found that subscribe method is not called when we have subscription options in ApolloServer instance. Removing the subscription option completely and the method is called. This is actually very weird because now I cannot define the separate path for subscription and cant call onConnect or onDisconnect methods as well.

@glasser
Copy link
Member

glasser commented Jul 20, 2021

The complexity of this issue was related to the fact that Apollo Server 2's subscriptions integration was relatively superficial. That integration has been removed from AS3; https://www.apollographql.com/docs/apollo-server/data/subscriptions/ shows how to integrate it yourself. We hope to do a more integrated subscriptions implementation some day; until then, issues about subscriptions will be closed.

@glasser glasser closed this as completed Jul 20, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 20, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
📝 documentation Focuses on changes to the documentation (docs)
Projects
None yet
Development

No branches or pull requests

10 participants