apollographql / meteor-integration

πŸš€ meteor add apollo
http://dev.apollodata.com/core/meteor.html
108 stars 45 forks source link

Configure subscriptions with graphql-subscriptions & subscriptions-transport-ws #85

Closed xavxyz closed 7 years ago

xavxyz commented 7 years ago

Summary

βš—οΈ This PR makes it easy for one using meteor/apollo to:

Usage

Client-side usage:

const networkInterface = createMeteorNetworkInterface({ enableSubscriptions: true });

const client = new ApolloClient(meteorClientConfig({ networkInterface });

Server-side usage:

createApolloServer({
  schema,
  pubsub,
  context,
});

Notes

In order to handle the current user client & server-side, I've moved the related logic to an accounts.js file:

Conclusion

On my way to write docs & tests πŸ™†β€β™‚οΈ

What are your thoughts? πŸ”₯

smeijer commented 7 years ago

This would be so awesome! It feels to me like the last missing piece to make it all fit together.

lorensr commented 7 years ago

Looking great! I like the usage. In the docs, I'd also mention:

import { PubSub } from `graphql-subscriptions`;
export const pubsub = new PubSub();

We allow overriding of '/graphql' – should we do the same for '/subscriptions'?

Minor point, but I think this line:

import { getMeteorLoginToken } from './accounts';

means that addCurrentUserToContext is unnecessarily bundled to the client?

xavxyz commented 7 years ago

@smeijer thanks for the feedback πŸ™Œ

@lorensr thanks for the review & notes for the docs! Totally agreed with the heads up on subscriptions path and exports, I'll fix that tomorrow πŸ‘Œ

csillag commented 7 years ago

This is how I used to do the same (in TypeScript):

import { meteorClientConfig } from "meteor/apollo";
import { ApolloClient } from "apollo-client";

import {                                                                   
    SubscriptionClient, addGraphQLSubscriptions,                           
} from "subscriptions-transport-ws";                                       

const config = meteorClientConfig();

const getWebSocketURI = (graphqlURI: string) => {                          
    const url = new URL(graphqlURI);                                       
    url.protocol = "ws";                                                   
    url.port = "5000";                                                     
    url.pathname = "";                                                     
    return url.toString();                                                 
};                                                                         

const { networkInterface } = config;                                       
const { _uri: graphqlURI } = networkInterface;                             
const wsURI = getWebSocketURI(graphqlURI);                                 

// Create WebSocket client                                                 
const wsClient = new SubscriptionClient(                                   
    wsURI,                                                                 
    {                                                                      
        reconnect: true,                                                   
        connectionParams: {                                                
            // Pass any arguments you want for initialization              
        },                                                                 
    },                                                                     
);                                                                         

export const apolloClient = new ApolloClient({                             
        ...config,                                                         
    // Extend the network interface with the WebSocket                     
    networkInterface: addGraphQLSubscriptions(                             
        networkInterface,                                                  
        wsClient,                                                          
    ),                                                                     
});                                                                        

See if there is anything you want to pick from this...

smeijer commented 7 years ago

So, if I understand @helfer correctly in https://github.com/apollographql/core-docs/pull/260, we shouldn't use this in production? The pubsub system for graphql trough this integration package, is not the same as using Meteor publish / subscribe?

Can someone enlighten me?

xavxyz commented 7 years ago

@smeijer, yeah you should be careful about using the "subscriptions" part of this package in production at the moment. We'll look for easing the use of MQTT / Redis / graphql-rx in the upcoming week.

With GraphQL subscriptions, you get a similar feeling as with Meteor pub/sub for the end user, but it's slightly more things to set up for the developer.

smeijer commented 7 years ago

We'll look for easing the use of MQTT / Redis / graphql-rx in the upcoming week.

@xavcz do you have a follow up on that?

xavxyz commented 7 years ago

Yeah @smeijer it's: https://github.com/xavcz/meteor-graphql-rx-subscriptions

Else I would recommend to roll your own subscriptions like for any node app.

If you don't know how, there are great articles / tutorials on the Apollo blog or on Graphcool.

If you find an interesting pattern, please make a PR or a new package 🀸 happy hacking! ☺️

xavxyz commented 7 years ago

Like this one, frontend: https://medium.com/react-native-training/full-stack-react-native-development-using-graphcool-and-apollo-subscriptions-react-navigation-cdb3e1374c05

And this one, backend: https://dev-blog.apollodata.com/tutorial-graphql-subscriptions-server-side-e51c32dc2951

smeijer commented 7 years ago

@xavcz , I indeed did find some awesome doc's about how to use Redis, or MQTT. But it still feels strange. I know it's the way to go. And I do agree that it's much better for production app's. But when I compare it to "the meteor times", using publish / subscribe was so damn easy. And nobody told us that it shouldn't be used for production apps.

I think in a perfect world, meteor-integration would reuse the meteor socket / ddp for it's pub/sub. I know I'm going for Redis or Mosquitto, but this makes it a lot harder to get started on some projects for new-comers. That's why I was still looking for easy solutions that do scale to production.

Meteor only needed the removal of the insecure package, now we need to add things to bring it to production. That feels counter productive. But, that's kind of off topic here.

Thanks for the links! I'll take a look at these ones as well. And don't get me wrong. I'm a big fan of apollo and the direction it's going. (and meteor as well).

smeijer commented 7 years ago

Back to the performance issue in relation with the easy developer experience.

Would the new notifications api will be available in MongoDB 3.6, make easy and performant subscriptions possible?

https://jira.mongodb.org/browse/SERVER-13932

https://dzone.com/articles/new-driver-features-for-mongodb-36#notification-api

In the past, we’ve seen that MongoDB users deploy a Redis server on the side, just for the sake of event notifications, or they use Meteor to get notifications from MongoDB. In 3.6, these notifications will be a MongoDB builtin feature. If you were maintaining both Redis and MongoDB, soon MongoDB alone will meet your needs. And if you want event notifications but you aren’t using Javascript and don’t want to rely on Meteor, you can write your own event system in any language without reinventing Meteor.