Currently, this is just a placeholder for discussions. But as a quick progress report, I have gotten started on subscriptions this weekend and it's coming along quite nicely! Right now I have 2 variations in mind:
Websockets (lighthouse-subscriptions-ws) - The main goal of this package is to keep everything in PHP land. The WS server will be built with Ratchet. I've tested some things out and I'm able to get Playground to connect/disconnect to a Ratchet server successfully (using the same methods as subscriptions-transport-ws). The next step is to start pushing down messages from the server. Since a subscriber can subscribe to multiple subscriptions (lol), I need storage. So it will launch w/ InMemory and Redis storage out of the box, but it can also be extended (i.e., MySQL storage). Because of how far along I am, this will likely be the first package released.
Pusher (lighthouse-subscriptions-pusher) - Maintaining an websocket server for a massive project doesn't sound fun to me... so I want to include at least one third-party solution. graphql-ruby has a great solution for this, however, it does rely on a custom Link for Apollo to work with it. Relay Modern is mentioned too, but I haven't dived into the JS parts of that yet.
The coolest thing (I think) is the fact that I can create these packages completely separate from the main lighthouse repo by leveraging directives! So hopefully, the community will be able to create some great alternatives if you use a different 3rd party WS provider or if you have a solution that relies on something other than Ratchet (i.e., Node).
I currently don't have a timeline for this, it just being done after work hours and on the weekends but this weekend was pretty productive so I'm really hoping it won't be too long before I can get this in everyone's hands!
Initial Beta Release of lighthouse-ws
Hey @chrissm79 completely half baked thought here that is probably entirely down the wrong track, but is there any way to leverage Laravel echo as the websocket provider?
Also, what I'm most curious about here is what api you're looking at implementing for these in terms of the .graphql schema?
Hi @chrissm79,
Subscriptions is indeed my last number one feature for lighthouse, great to hear you're making progress! Since I currently have already a Node ws server running I'd be happy to see where I can help to get this up and running with it.
Redis is also my preferred store for queues and websocket storage..
I'll have a look at Ratchet as well. Interested also in a Laravel Echo implementation as mentioned by @hailwood
@hailwood @4levels Echo is a pretty interesting prospect, but I feel like I'm jamming a round peg through a square hole at the moment... specifically when attempting to customize data being sent down to the client based on the query they're subscribing to.
From my previous tests, I can send something like a Post model via the broadcast event, but what if the user subscribed to something like this:
subscription onPostCreated {
postCreated {
title
comments {
# ...
# How do we know that this client wants the post AND comments?
}
}
}
I don't see how I can adjust the broadcastWith method on the event based on the client's subscription request to include the comments or (and more importantly) use defined resolvers for each object type/field.
However, I REALLY like the idea of using Echo as it lowers the barrier of adoption even more so I will certainly circle back to it when the time comes!
At that point, isn't it functionally the same as executing the following?
{
post(id: [newPostIdFromTheEvent]) {
title
comments {
...
}
}
}
@TGNThump If you're asking if you could just send a query when a subscription gets sent down then yes, but then you don't even need GraphQL subscriptions, you could just use Echo and pull down/refetch when a certain event is fired.
However, that's not the purpose of GraphQL subscriptions (or Echo really) since that means that you have everyone pulling from your server at the same time when the event fires rather than having the data they want pushed down to them.
@chrissm79, no I meant executing on the server, but I suppose the problem would be that the broadcastWith would be different for each client... I see where you're coming from.
I suppose you'd have to use a separate channel / echo event for every subscription by every client.
@TGNThump sorry for the misunderstanding, but yes you're dead on! I think it's possible, it's just more efficient to go in another direction for now and then come back and see if I can tackle Echo (i.e., maybe making a custom queue driver).
I've gotten subscriptions working with lighthouse by setting up a Ratchet\WebSocket server that runs on a Laravel Command and conforms to the https://github.com/apollographql/subscriptions-transport-ws protocol.
I fire an event on a subscription using a custom directive to make my schema cleaner, but using @event would work just as well. All the event listener does is connect to the websocket server and send over the event data.
The websocket server is handling storing the users Passport token and verifying it before every subscription / event and pushing data to the clients by calling graphql()->execute() for each subscription. I modified the Context class to include an $event variable that contains the event passed to the server, and passed to the subscription resolvers.
WebsocketController: https://gist.github.com/TGNThump/8865041b4626fe00a0c45a087ff82a32
@TGNThump, damn that looks nice! The only thing I had left on my version was generating and storing the context, but it's pretty verbose and I needed to clean things up quite a bit before release. Your solution looks extremely streamlined and easy to understand 👍 I'll check it out in depth but thank you for providing this!!!
Figure I might as well integrate it the whole way.
Here is the first beta release for lighthouse-ws! Currently, it requires Redis, it works w/ Passport to inject the authenticated user into context, and provides an in-memory storage solution for subscriptions. You can extend the SubscriptionManager (for storage) and ContextManager (to generate your own context) if you prefer to create your own solutions here. Before the v1.0 release RedisStorage will be available.
Subscription events can be broadcasted using the custom broadcaster lighthouse (which will fire a subscription event when any Laravel event is triggered) and implements the ShouldBroadcast interface or you can use the @websocket directive to send any mutation result over to lighthouse-ws.
The @subscription directive works similar to @field. Your subscription classes should extend the Nuwave\Lighthouse\Subscriptions\Schema\Fields\SubscriptionField class and define a resolve function. You can also define a can function to allow/reject clients from subscribing to certain subscriptions and a transform method to transform the event that was fired over Redis. Before the v1.0 release I'll create a default SubscriptionField class if none is defined that will just pass along whatever was sent via the event.
Big shout out to @TGNThump for providing some great direction on the initial structure!
Hi @chrissm79,
I'm finally able to get my hands dirty on this, but I'm a bit struggling how to go about, well, everything :confused:
Let's say I want my end users to be able to subscribe to eg. a list of posts so that as soon as a post is added by someone, everyone gets the new post.
Am I supposed to simply do composer require nuwave/lighthouse-ws in my current project (alongside with lighthouse itself)?
And how do I then define a subscription directive in the schema?
What do I need to run to have lighthouse-ws actually spin up a websocket server (listening to the redis queue)? And how do I trigger the broadcast?
Sorry for asking pbbly very obvious instructions here..
Since I'm using Lumen, this is what I've done so far:
composer require nuwave/lighthouse-wsconfig/lighthouse_subscriptions.phpbootstrap/app.php$app->configure('lighthouse_subscriptions');boostrap/app.php:$app->register(\App\Providers\EventServiceProvider::class);$app->register(\Illuminate\Redis\RedisServiceProvider::class);$app->register(\Illuminate\Broadcasting\BroadcastServiceProvider::class);$app->register(\Nuwave\Lighthouse\Subscriptions\SubscriptionServiceProvider::class);So when I run php artisan lighthouse:subscriptions I do get the following output (in purple):
18/05/19 22:55:48| | |Starting Websocket Service on port 9000 - 0
18/05/19 22:55:48| | |Connected to Redis.
FYI I'm using React Native as a frontend for all this and so far I got everything playing along nicely with Lighthouse, super amazed how lighthouse just delivers on the graphql backend part. I simply can't stop talking to people about this (even if they don't even have a clue)!
Hello @chrissm79, superb work you have done on this so far. Kudos!
Please, is there any chance we might get a video walkthrough for Subscriptions? I believe one would be very apt. Thank you!
is there a way to fire subscriptions events without @event directive?
I love this!!!
Its great to connect with pusher through lighthouse. Is there anyway to connect with PHP Swoole ?
Is this valid today? For version 4.0
Subscriptions are implemented as of Lighthouse v3.
using graphql-playground the next error appears:
{
"error": "Could not connect to websocket endpoint ws://localhost/project/public/graphql. Please check if the endpoint url is correct."
}
Subscriptions in Lighthouse are based on the ruby implementation which is not supported by Playground (or any other GraphQL IDE that I'm aware of).
In order to make it work with Playground you would have to create your own websocket server which implements the same implementation as apollo-server. Similar to lighthouse-ws which has been depreciated.
thanks, great job with this package :+1:
You can get it running with laravel websockets as well, at least I can run
queries in grapqhl playground for quite some time now.
Subscriptions seem to work as I do get subscription nodes in the responses
but the subscriptions integration in grapqhl playground doesn't seem to
work so far. I haven't been working on all this for a while now but it
should be possible to make laravel websockets work as well. I created an
issue once in their repo asking about graphql support. It should be
possible to make it work though.. I also never managed to get a relay
subscription up and running in react either, fwiw.
Setting up a wss server locally involves quite some things though, there be
dragons..
Keep us posted on your progress!
On Wed, 26 Jun 2019, 21:56 seedgabo, notifications@github.com wrote:
thanks, great job with this package 👍
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/nuwave/lighthouse/issues/88?email_source=notifications&email_token=AABRQPGHGTJ3XQXGVF4B5HLP4PCXJA5CNFSM4E34ZE42YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODYUURFA#issuecomment-506022036,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AABRQPBLNHQJCIBZNKHOVP3P4PCXJANCNFSM4E34ZE4Q
.
Subscriptions in Lighthouse are based on the ruby implementation which is not supported by Playground (or any other GraphQL IDE that I'm aware of).
In order to make it work with Playground you would have to create your own websocket server which implements the same implementation as apollo-server. Similar to lighthouse-ws which has been depreciated.
@chrissm79
How can i create websocket server which connect with lighthouse graphql subscription ?
Subscriptions have been implemented for quite some time, so i am locking this issue. Use Slack or Stackoverflow for support questions. Bugs or new features can be adressed in either a new issue or a PR.
Most helpful comment
Here is the first beta release for lighthouse-ws! Currently, it requires Redis, it works w/ Passport to inject the authenticated user into context, and provides an in-memory storage solution for subscriptions. You can extend the SubscriptionManager (for storage) and ContextManager (to generate your own context) if you prefer to create your own solutions here. Before the v1.0 release RedisStorage will be available.
Subscription events can be broadcasted using the custom broadcaster
lighthouse(which will fire a subscription event when any Laravel event is triggered) and implements theShouldBroadcastinterface or you can use the@websocketdirective to send any mutation result over tolighthouse-ws.The
@subscriptiondirective works similar to@field. Your subscription classes should extend theNuwave\Lighthouse\Subscriptions\Schema\Fields\SubscriptionFieldclass and define aresolvefunction. You can also define acanfunction to allow/reject clients from subscribing to certain subscriptions and atransformmethod to transform the event that was fired over Redis. Before thev1.0release I'll create a defaultSubscriptionFieldclass if none is defined that will just pass along whatever was sent via the event.Big shout out to @TGNThump for providing some great direction on the initial structure!