The server sees client connecting successfully, but the client gets the error, even if nothing is published from server.
Meteor's WebApp is the HTTP server.
import { ApolloServer } from 'apollo-server-express'
import { typeDefs } from './schema.js'
import { resolvers } from './resolvers.js'
import { DSBooks } from "./DSBooks.js"
import { getUser } from 'meteor/apollo'
const server = new ApolloServer({
typeDefs,
resolvers,
dataSources: () => ({
dsBooks: new DSBooks()
}),
context: async ({ req }) => ({ user: await getUser(req.headers.authorization) }),
uploads: false,
subscriptions: {
path: "/subscriptions",
onConnect: async (connectionParams, webSocket, context) => {
console.log(`Subscription client connected using Apollo server's built-in SubscriptionServer.`)
},
onDisconnect: async (webSocket, context) => {
console.log(`Subscription client disconnected.`)
}
}
})
import { WebApp } from 'meteor/webapp'
server.applyMiddleware({ app: WebApp.connectHandlers }) //path option defaults to /graphql
WebApp.connectHandlers.use('/graphql', (req, res) => { if (req.method === 'GET') res.end() }) // To prevent server-side exception "Can't set headers after they are sent" because GraphQL Playground (accessible in browser via /graphql) sets headers and WebApp also sets headers
server.installSubscriptionHandlers(WebApp.httpServer)
If I start a new SubscriptionServer instead, there's no problem, and the client receives subscription data.
import { ApolloServer } from 'apollo-server-express'
import { typeDefs } from './schema.js'
import { resolvers } from './resolvers.js'
import { DSBooks } from "./DSBooks.js"
import { getUser } from 'meteor/apollo'
const server = new ApolloServer({
typeDefs,
resolvers,
dataSources: () => ({
dsBooks: new DSBooks()
}),
context: async ({ req }) => ({ user: await getUser(req.headers.authorization) }),
uploads: false,
})
import { WebApp } from 'meteor/webapp'
server.applyMiddleware({ app: WebApp.connectHandlers }) //path option defaults to /graphql
WebApp.connectHandlers.use('/graphql', (req, res) => { if (req.method === 'GET') res.end() }) // To prevent server-side exception "Can't set headers after they are sent" because GraphQL Playground (accessible in browser via /graphql) sets headers and WebApp also sets headers
import { SubscriptionServer } from 'subscriptions-transport-ws'
import { execute, subscribe } from 'graphql'
import { makeExecutableSchema } from 'graphql-tools'
SubscriptionServer.create(
{
schema: makeExecutableSchema({ typeDefs, resolvers }),
execute,
subscribe,
onConnect: async (connectionParams, webSocket) => {
console.log(`Subscription client connected using new SubscriptionServer.`)
},
onDisconnect: async (webSocket, context) => {
console.log(`Subscription client disconnected.`)
}
},
{
server: WebApp.httpServer,
path: "/subscriptions",
},
)
Code showing ApolloClient creation:
import ApolloClient from 'apollo-client'
import { ApolloLink } from 'apollo-link'
import { MeteorAccountsLink } from 'meteor/apollo'
import { HttpLink } from 'apollo-link-http'
import { WebSocketLink } from 'apollo-link-ws'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { Meteor } from "meteor/meteor"
const apolloClient = new ApolloClient({
link: ApolloLink.split( // split based on operation type
({ query }) => {
import { getMainDefinition } from 'apollo-utilities'
const { kind, operation } = getMainDefinition(query)
return kind === 'OperationDefinition' && operation === 'subscription'
},
new WebSocketLink({
uri: `${Meteor.absoluteUrl("/subscriptions").replace("http", "ws")}`,
options: { reconnect: true }
}),
ApolloLink.from([
new MeteorAccountsLink(),
new HttpLink({ uri: '/graphql' })
]),
),
cache: new InMemoryCache()
})
Both apolloClient.subscribe() and the Subscription React component produce the same error.
hey @tab00 had the same exception, you could start looking here. I didn't have any headers on the websockets (subscriptions):
context: async ({ req }) => ({ user: await getUser(req.headers.authorization) })
async context(val) {
console.log(val && val.req)
}
This problem still exists. Please fix it.
Should you use req when using subscriptions? Docs point out that you should use connection to create context from a subscription https://www.apollographql.com/docs/apollo-server/v2/features/subscriptions.html#Context-with-Subscriptions
I still get this problem. Has anyone tried to fix this?
@almostprogrammer is correct. I structured my ApolloServer code below and it works. for subscription, you don't use req. u need to use connection
details https://github.com/apollographql/graphql-subscriptions/blob/master/.designs/authorization.md
const server = new ApolloServer({
typeDefs,
resolvers,
context: async ({ req, connection }) => {
if (connection) {
return {
...connection.context,
pubsub
};
} else {
const token = req.headers["authorization"] || "";
return {
User,
Tweet,
Comment,
pubsub,
userId: await getUser(token)
};
}
}
});
@myhendry, why isn't there subscriptions in the argument list of your ApolloServer instantiation?
They are all in my resolvers file
https://github.com/myhendry/template/blob/master/server/graphql/resolvers.js
It looks like returning ...connection.context fixed the problem, so thank you @myhendry for the code.
Though I still needed to add
subscriptions: {
path: "/subscriptions"
in the ApolloServer arguments object, otherwise I think the built-in subscription server wouldn't start.
So my code is now:
import { ApolloServer } from 'apollo-server-express'
import { typeDefs } from './schema.js'
import { resolvers } from './resolvers.js'
import { DSBooks } from "./DSBooks.js"
import { getUser } from 'meteor/apollo'
const server = new ApolloServer({
typeDefs,
resolvers,
dataSources: () => ({
dsBooks: new DSBooks()
}),
context: async ({ req, connection }) => {
if (connection) {
return {
...connection.context
};
}
uploads: false,
subscriptions: {
path: "/subscriptions",
onConnect: async (connectionParams, webSocket, context) => {
console.log(`Subscription client connected using Apollo server's built-in SubscriptionServer.`)
},
onDisconnect: async (webSocket, context) => {
console.log(`Subscription client disconnected.`)
}
}
})
import { WebApp } from 'meteor/webapp'
server.applyMiddleware({ app: WebApp.connectHandlers }) //path option defaults to /graphql
WebApp.connectHandlers.use('/graphql', (req, res) => { if (req.method === 'GET') res.end() }) // To prevent server-side exception "Can't set headers after they are sent" because GraphQL Playground (accessible in browser via /graphql) sets headers and WebApp also sets headers
server.installSubscriptionHandlers(WebApp.httpServer)
I am not using meteor. I am using node js. I haven't tried using meteor
with graphql
On Sat, Feb 9, 2019, 10:04 PM tab00 notifications@github.com wrote:
Closed #1537 https://github.com/apollographql/apollo-server/issues/1537.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/apollographql/apollo-server/issues/1537#event-2128747030,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ATr8G64YYZCcvQmeVkO5UNeYo2rGU75eks5vLtWFgaJpZM4V-Pgx
.
@helfer the problem here is that SubscriptionServer calls this.context({ connection, payload: message.payload }), hence req is undefined in OP's context function. The only documentation on the website for context shows it being called with the (req, res) from an HTTP request; I can't find any documentation of it being called by SubscriptionServer. Seems like this is either a mistake or the documentation needs to be fixed?
@helfer to make matters worse, https://github.com/apollographql/apollo-server/blob/master/packages/apollo-server-core/src/ApolloServer.ts#L480 overwrites the context returned by subscriptions: { onConnect: async (connectionParams: any) => { ... } } that is recommended in the docs on the website.
This is a major issue.
It seems like the developers working on the ApolloServer 2 refactor weren't all on the same page?
same here its overwrites context with null. I set subscribed user on Connect. When i try in resolvers, its seems undefined.


I found a solution Context must be used with connection.context check here.

https://github.com/apollographql/apollo-server/issues/1796#issuecomment-429237068
@tab00 I documented in #2315 how I think the way both HTTP and Websockets call the context function causes more confusion than it's worth
Thanks for reporting this issue originally!
I'm going to close this issue since it hasn't received a lot of traction and could have been resolved already.
If this is still a problem, would someone who's experiencing the problem (or anyone who comes across this issue and is able to assist) mind building a reproduction of the problem in to a runnable CodeSandbox reproduction using the latest version of Apollo Server and sharing the link to that CodeSandbox in this issue?
I'm happy to re-open if this is still occurring and someone can provide a reproduction. Thanks again!
This is still an issue for most people who setup auth with subscriptions.
It's possible to get it working but really not as easy as it should be.
Please see #2315 for proposed api change. Other related issue: #1597
This is a running sandbox showing the problem: https://codesandbox.io/s/apollo-server-qthfh?fontsize=14
@StefanFeederle that seems like the wrong issue number, mind checking it?
@jedwards1211 Thanks, fixed it
Is this dead? I'm having issues with receiving the connection param from context. I'm using websockets for auth If that's relevent.
Most helpful comment
@almostprogrammer is correct. I structured my ApolloServer code below and it works. for subscription, you don't use req. u need to use connection
details https://github.com/apollographql/graphql-subscriptions/blob/master/.designs/authorization.md