folkloreinc / laravel-graphql

Facebook GraphQL for Laravel 5. It supports Relay, eloquent models, validation and GraphiQL.
1.76k stars 234 forks source link

How to make graphql subscriptions? #167

Open bigperson opened 7 years ago

bigperson commented 7 years ago

How can I use this package for make graphql subscriptions?

SonarSoftware commented 7 years ago

I am very interested in this as well, is it on the roadmap?

n1ru4l commented 7 years ago

Related: https://github.com/webonyx/graphql-php/issues/9

In short, there are two options:

  1. Use http://reactphp.org/ (or similar) to run a websocket server and have your users connect to that

  2. Run websocket server in node and write stuff to a redis inside your laravel app and push it with node to your clients. There are implementations like https://www.npmjs.com/package/graphql-redis-subscriptions, that could be inspiring for implementing this.

The simplest implementation would be to write incoming subscriptions into a redis list (with a node.js process) that runs a websocket server.

Then laravel-graphql could provide an interface to push data for a given subscription e.g. identified by operationName into a redis queue.

The subscription itself would also need a resolver function to map the pushed data to a graphql type or scalar.

With a huge amount of subscriptions you should definitely not process the subscriptions in the ongoing request.

Therefore you need a second worker process (must be php in order to execute the graphql schema) that listens to the redis queue (maybe this process could also implement the websocket server? I do not know about any php websocket implementations neither heard of anyone who is using them). This worker executes the data against the schema and writes the results to another redis queue on which our node websocket process listens to. (This could also be handled by a cron job, depending on the desired delay)

The node process then pushes the data to the clients.

You will also have to think about mapping the node processes websocket to a subdomain or url with ngnix (or apache).

This are my first thoughts for implementing subscriptions with php. If you have any additions or think I am overcomplicating things: I am open to feedback.

I am using the library at work for a graphql server that does not have any requirements for subscriptions, therefore it is very unlikely that I am going to work on this feature (although I would be interested to do it if we need it.). On private projects I am using node.js for every graphql server that I have written so far (It is way more comfortable than in PHP btw.).

SonarSoftware commented 7 years ago

I would expect to have to implement the actual resolution of subscriptions on my side (although some helper to pass in data and return the query parameters only would be helpful, basically the equivalent of the 'resolve' function on a query.)

Really all I would want is some standardized way to register a subscription to the schema, a way to define where the subscription request goes, and a resolution function. Now that I write it out, it doesn't sound like it would be terribly hard to implement - I just don't want to build it all myself if it is already half done or close to being released officially :)

n1ru4l commented 7 years ago

Therefore we need a Subscription class (similar to the query class) and an Abstract Subscription(Publisher/Transport) class that you then would use with redid or whatever. I think the first place to start with this is to make this part of graphql-php and then move forward to add support here

SonarSoftware commented 7 years ago

Yes, that's exactly what I'm thinking. In fact, I would hazard a guess that a subscription can really just implement an existing query class, but the 'subscription' prefix would trigger a different resolution (which would be to push some kind of subscription class, like you mentioned.) I could then handle that object however I pleased (similarly to how we implement our own resolutions today) and broadcast the data to the client. It could be possible to build some standardized/example implement using something like Laravel Echo or Ratchet as an example, but I think simply having a standard way to define a subscription and a model definition for the subscription request is probably enough.

SonarSoftware commented 7 years ago

I'm going to have to start working on this for myself soon. I will fork and submit a PR when done, but I'm not sure it will be abstract enough for everyone - willing to give it a shot. My basic plan is as follows:

When a subscription is submitted, the query parameters will be stored and broadcast using Laravel eventing. I'll have to build some abstract way to determine whether or not a specific entity is subscribed (e.g. if account ID 4 is modified, who has subscribed to it?) This'll probably be some check that I'll implement in my observers, and I'll have a service that will return a list of subscribed parties. If a party is subscribed, I'll resolve the original query using the new entity, and broadcast something to my websocket system to be sent to the original subscriber. This will then get pushed to them as a websocket update and the client will handle it.

Chunks of this are just going to be too abstract to build as a hard path. Really all I see having from a baked in perspective is:

1) A method of subscribing/unsubscribing 2) Some mechanism to determine whether or not a particular type/ID has been subscribed to. 3) Some method to store and resolve the original query against the new data.

I think the utilization of 2, and the broadcasting method used in 3 are going to be too application dependent to have anything more than that around them. Appreciate any feedback.

r-moiseev commented 7 years ago

Is it possible to use Echo Server for this? It looks pretty native to laravel

bigperson commented 7 years ago

@r-moiseev I use Echo Server, but I have to use Vuex Store and change data through mutations, when events are triggered. I think that this is a bad decision.

codeitlikemiley commented 6 years ago

im also looking into this, since i wanna implement it with laravel echo, hope this have a Subscription Class that Will be triggered when a mutation happens, this can be useful for example you update a product info, and want your user be able to see the changes right away, even if the content is cached

matrunchyk commented 6 years ago

@SonarSoftware any update on it?

SonarSoftware commented 6 years ago

No, I ended up finding that subscriptions weren't really a good solution for my needs. I went in a different direction.

mfn commented 6 years ago

You might be interested that lighthouse is currently working on an implementation, still a PR though : https://github.com/nuwave/lighthouse/pull/337