GraphQLBundle
GraphQLBundle copied to clipboard
subscriptionType ?
| Q | A |
|---|---|
| Bug report? | no |
| Feature request? | yes |
| BC Break report? | no |
| RFC? | no |
| Version/Branch | x.y.z |
is there a possibility to add subscription type to the bundle or make another compatible bundle like the data loader i think this would be possible with a library like ratchet they already discussed the issue in webonyx https://github.com/webonyx/graphql-php/issues/9
webonyx/graphql-php is the best place to debate about this, the bundle is just the symfony implementation. This feature is requiring a direct implementation in the main lib... Maybe using this https://siler.leocavalcante.com/graphql/subscriptions.html could also helps...
feel free to reopen if needed...
sorry for reopening this issue after a long time, i decided to implement subscription on top of your bundle, siler's example works when you create a symfony command that runs ratchet on a different port, i can pass the schema to the websocket server, however subscription resolvers need to take the payload in the function argument instead of the query variables, and i found some difficulties to add a new type of resolvers to your bundle,
@omarsoufiane can you provide some snippets of the issue please ?
first graphiql and react needs a higher default version on the config and subscription types work by default `overblog_graphql:
versions:
graphiql: 0.9.3
react: 15.4.2
definitions:
schema:
query: Query
mutation: Mutation
subscription: Subscription`
you need a class with a subscribe and publish method that we will register as a service to use it in the sumfony command and mutation resolver
`use GraphQL\Schema;
use Ratchet\Client; use Ratchet\Client\WebSocket; use Ratchet\Http\HttpServer; use Ratchet\Server\IoServer; use Ratchet\WebSocket\WsServer;
const INIT = 'init'; const INIT_SUCCESS = 'init_success'; const INIT_FAIL = 'init_fail'; const SUBSCRIPTION_START = 'subscription_start'; const SUBSCRIPTION_END = 'subscription_end'; const SUBSCRIPTION_SUCCESS = 'subscription_success'; const SUBSCRIPTION_FAIL = 'subscription_fail'; const SUBSCRIPTION_DATA = 'subscription_data';
class Subscription {
protected $host;
protected $port;
/**
* SubscriptionCommand constructor.
* @param $host
* @param $port
*/
public function __construct($host, $port)
{
$this->host = $host;
$this->port = $port;
}
/**
* Returns a new websocket server bootstraped for GraphQL subscriptions.
*
* @param Schema $schema
* @param array $filters
* @param array $rootValue
* @param array $context
* @param int $port
* @param string $host
* @return IoServer
*/
function subscribe(
Schema $schema,
array $filters = null,
array $rootValue = null,
array $context = null,
$port = 7070,
$host = '0.0.0.0'
) {
$manager = new SubscriptionManager($schema, $filters, $rootValue, $context);
$server = new SubscriptionServer($manager);
$websocket = new WsServer($server);
$websocket->disableVersion(0);
$http = new HttpServer($websocket);
return IoServer::factory($http, $port, $host);
}
/**
* Publishes the given $payload to the $subscribeName.
*
* @param string $subscriptionName
* @param mixed $payload
*/
function publish($subscriptionName, $payload = null)
{
Client\connect('ws://127.0.0.1:7070')->then(function (WebSocket $conn) use ($subscriptionName, $payload) {
$request = [
'type' => SUBSCRIPTION_DATA,
'subscription' => $subscriptionName,
'payload' => $payload,
];
$conn->send(json_encode($request));
$conn->close();
});
}
}`
then create a command that runs the websocket server on a different port
`class SubscriptionCommand extends ContainerAwareCommand { /** * Configure a new Command Line */ protected function configure() { $this ->setName('graphql:subscription:server') ->setDescription('Start the notification server.') ->addOption( 'file', null, InputOption::VALUE_OPTIONAL, 'Path to generate schema file.' ) ->addOption( 'schema', null, InputOption::VALUE_OPTIONAL, 'The schema name to generate.' )
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$output = new SymfonyStyle($input, $output);
$container = $this->getContainer();
//the problem is here i guess, the schema already has resolvers and they don't accept payloads as //function argument $schema = $container ->get('overblog_graphql.request_executor') ->getSchema();
//filters is a way to know which subscription should recieve data after you send a mutation as explained in siler
$filters = [
'inbox' => function ($payload, $vars) {
return ($payload['roomid'] == $vars['roomid']) ;
},
];
$subscription = $container->get('subscription_command');
$subscription->subscribe($schema, $filters)->run();
}
}`
subscription server and subscription manager are two files i got from siler: https://github.com/leocavalcante/siler/tree/master/src/Graphql
since they rely on a function specific to the framework yo need to add it
` /* * array get function imported from sliler root */
public function array_get($array, $key = null, $default = null)
{
if (is_null($key)) {
return $array;
}
return array_key_exists($key, $array) ? $array[$key] : $default;
}`
thank you for the example. I don't have a lot of time to work on that right now but hope to get a look more carefully on this before the weekend...