GraphQLBundle icon indicating copy to clipboard operation
GraphQLBundle copied to clipboard

subscriptionType ?

Open omarsoufiane opened this issue 8 years ago • 7 comments

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

omarsoufiane avatar May 18 '17 01:05 omarsoufiane

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...

mcg-web avatar May 24 '17 21:05 mcg-web

feel free to reopen if needed...

mcg-web avatar May 30 '17 07:05 mcg-web

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 avatar Aug 12 '17 01:08 omarsoufiane

@omarsoufiane can you provide some snippets of the issue please ?

mcg-web avatar Aug 16 '17 06:08 mcg-web

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();
}

}`

omarsoufiane avatar Aug 17 '17 03:08 omarsoufiane

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;
}`

omarsoufiane avatar Aug 17 '17 03:08 omarsoufiane

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...

mcg-web avatar Aug 22 '17 06:08 mcg-web