Apollo Integration with Meteor

Hi, I’ve been hunting and searching high and low to get a Meteor/Apollo/React integration working with subscriptions, but I’ve not been able to get any proper working version of it.

The v2 docs used to have a page for the Meteor integration but it is non-existent in the v3 docs.

I managed to get close once, with the following setup:

Client:

const client = new ApolloClient({
    link: new DDPLink(),
    cache: new InMemoryCache()
})

const ApolloApp = () => (
    <BrowserRouter>
        <ApolloProvider client={client}>
            <App />
        </ApolloProvider>
    </BrowserRouter>
)

Meteor.startup(() => {
    render(<ApolloApp />, document.getElementById("app"))
})

Server:

const schema = makeExecutableSchema({
    typeDefs,
    resolvers,
})

setup({
    schema
})

This was done with the swydo:ddp-apollo package. This uses Meteor’s DDP link instead of creating a new WebSocket connection.

But there are a few limitations:

  1. I cannot use Graphiql if I do this. The Graphiql tab in Apollo Client DevTools is blank as well (even without using this code for the client/server). If I use my old code which does not support subscriptions, Graphiql works fine but the Apollo Client DevTools extension is still bugged. I’ve filed a bug report on this front, but this is still a limitation I’m currently facing.
  2. I observed the Network tab and I noticed that every query, mutation and subscription uses a WebSocket link. Isn’t it inefficient to have everything go through a WebSocket link? That means that every single user connected to my website will have a perpetually open WebSocket link, even when I only need it for subscriptions. Queries and mutations go through the same link. Will that scale correctly?

Appreciate any help, thank you.

EDIT: Not sure why this was flagged as spam?

@ajaypillay The Meteor integration docs were removed as they were out of date, and Meteor and Apollo Client are no longer maintained by the same people. Regarding your specific questions:

  1. If you’ve opened an issue in the AC devtools repo, that’s great. We’ll take a look.
  2. Take a look in the Apollo Client subscription docs, the Split communication by operation section in particular. It shows you how to use split to prevent all operations from going over a WebSocket.
1 Like

Thank you for your response and the information.

  1. I did not personally open the issue, someone else opened the issue a couple of weeks ago.

  2. Thank you for the link, I will look into this. Is the idea that I use both an HttpLink and a DDPLink, and I split to ensure not all operations go over WebSocket (through DDP)?

If that is the idea, I will update if I manage to get this working, thank you for the help.

EDIT: I’m not sure why this was flagged as spam too.

Correct - unless of course you want everything going over a WebSocket.

1 Like

@hwillson I’m not sure if I’m understanding how to do this correctly. As per the swydo:ddp-apollo docs, I have my server set up as such:

const schema = makeExecutableSchema({
    typeDefs,
    resolvers,
})

setup({
    schema
})

And for the client, if I already have an HTTP server set up:

const httpLink = new HttpLink({
    uri: "http://XXX.XXX.XX.XX:3000/graphql"
})
const subscriptionLink = new DDPSubscriptionLink()
const link = split(
    isSubscription,
    subscriptionLink,
    httpLink
)

const client = new ApolloClient({
    link,
    cache: new InMemoryCache()
})

const ApolloApp = () => (
    <BrowserRouter>
        <ApolloProvider client={client}>
            <App client={client} />
        </ApolloProvider>
    </BrowserRouter>
)

Meteor.startup(() => {
    render(<ApolloApp />, document.getElementById("app"))
})

In App.js I ran a query (no subscriptions or anything of the sort have been initiated). But in the Network tab I see this:
image

(I can’t upload a second image but there is a graphql query sent as well)

  1. For some reason, even though I’m using split, a WebSocket connection is open and a normal query is being run through HTTP.
  2. The normal query fails because XXX.XXX.XX.XX/graphql is not longer the graphql endpoint (visiting that URL does not open Graphiql anymore, the query returns raw HTML)

Would you be able to advise how to proceed from here? I’ve tried many different combinations of the client/server code as stated in the DDP-Apollo docs but none of them work correctly. The portion I followed above is of interest because of the fact that it’s supposed to split the connections correctly.

Okay @hwillson I have gotten much farther than I have before. My server code is as follows:

const schema = makeExecutableSchema({
    typeDefs,
    resolvers,
})

const context = async ({req}) => ({
    user: await getUser(req.headers.authorization)
})
const server = new ApolloServer({
    schema,
    context,
    subscriptions : {
        path: '/subscriptions'
    }
})

server.applyMiddleware({
    app: WebApp.connectHandlers,
    path: "/graphql",
})

WebApp.connectHandlers.use("/graphql", (req, res) => {
    if (req.method === "GET") {
        res.end()
    }
})

This is the default server configuration, not the one recommended in swydo:ddp-apollo. My client code is as follows:

const httpLink = new HttpLink({
    uri: "http://XXX.XXX.XX.XX:3000/graphql"
})
const authLink = new ApolloLink((operation, forward) => {
    const token = Accounts._storedLoginToken()
    operation.setContext(() => ({
        headers: {
            authorization: token
        }
    }))
    return forward(operation)
})
const subscriptionLink = new DDPSubscriptionLink()
const splitLink = split(
    isSubscription,
    subscriptionLink,
    httpLink
)
const client = new ApolloClient({
    link: from([authLink, splitLink]),
    cache: new InMemoryCache()
})

const ApolloApp = () => (
    <BrowserRouter>
        <ApolloProvider client={client}>
            <App client={client} />
        </ApolloProvider>
    </BrowserRouter>
)
Meteor.startup(() => {
    render(<ApolloApp />, document.getElementById("app"))
})

Now in the Network tab, I see the graphql operations being executed as and when they are needed. However, there is still a WebSocket connection open. I am starting to think this is the WebSocket connection Meteor uses as part of its DDP, although I am not entirely sure. When I remove the DDPSubscriptionLink, I notice that the WebSocket connection is still there, which is why I believe that’s under Meteor’s purview.

I can access localhost:3000/graphql but I can’t execute any subscriptions. I get the error that:

{
  "error": "Could not connect to websocket endpoint ws://XXX.XXX.XX.XX:3000/subscriptions. Please check if the endpoint url is correct."
}

How might I go about remedying this? Is there something wrong in my setup somewhere? Appreciate any help.