graphql-compose / graphql-compose-subscription-boilerplate

GraphQL-compose boilerplate with subscriptions
11 stars 1 forks source link

How to use graph-ws instead #3

Open ziedHamdi opened 3 years ago

ziedHamdi commented 3 years ago

Hi,

Thanks for this project that simplifies the burden on how to setup subscription. My issue is that it relies on subscriptions-transport-ws which is deprecated to the benefit of https://the-guild.dev/blog/graphql-over-websockets as mentioned on their npm page:

The subscriptions-transport-ws library is not being actively maintained. It is recommended that you use the graphql-ws library instead. For details read the GraphQL over WebSockets announcement.

So I'm struggling about how to get the roots of my gql schema from the object returned by schemaComposer.buildSchema()

subscriptionServer.js

import ws from 'ws'; // yarn add ws
import { useServer } from 'graphql-ws/lib/use/ws';
const GraphQlSchema = require('./graphql').default

//redis must be running
const server = new ws.Server({
    port: 4001,
    path: '/subscribe',
});

useServer(
    // from the previous step
    { schema: GraphQlSchema, roots: GraphQlSchema },
    server
);

console.log('Listening to port 4001');
ziedHamdi commented 3 years ago

Can you please guide me from where to start my investigation, I'll post the answer if I find it

nodkz commented 3 years ago

Nothing to do with roots just pass an empty object to it. The schema already contains everything that is needed.

nodkz commented 3 years ago
useServer(
    // from the previous step
    { schema: GraphQlSchema, roots: {} },
    server
);
ziedHamdi commented 3 years ago

Hi Paul,

Sorry for the late reply, I had issues with docker, I was unable to test.

I tried your solution today, the server starts flawlessly. However, I have an issue with the resolvers: 2nd and 3rd arguments are not passed anymore: in the following example arg2 and context are both null

ComplaintTC.addFields({
    userActionRecap: {
        type: ActionRecapList,
        resolve: async (complaint, arg2, context) => {
            logger.debug( "complaint :", complaint, "arg2 : ", arg2, " context: ", context )
            const userRecap = await findUserActionRecaps(complaint, arg2, context);
            return userRecap
        }
    }
})

Here's my server init code for refrerence:

import ws from 'ws'; // yarn add ws
import { useServer } from 'graphql-ws/lib/use/ws';
const GraphQlSchema = require('./graphql').default

const server = new ws.Server({
    port: 4001,
    path: '/subscribe',
});

useServer(
    { schema: GraphQlSchema, roots: {} },
    server
);
ziedHamdi commented 3 years ago

Hi Paul,

I received this answer from the GraphQL-ws team: https://github.com/enisdenjo/graphql-ws/discussions/223#discussioncomment-1157903

This is what he writes: To provide a contextValue to graphql resolvers, you have to supply the context option. Please check the "ws server usage with custom context value" recipe.

The roots option is a convenience that gets injected to the rootValue during graphql's execute or subscribe by operation type. graphql-ws/src/server.ts

Line 738 in f2a92af

execArgs.rootValue = roots?.[operationAST.operation];

In your case (from the referenced issue), the roots option can be completely omitted as it does nothing anyway. arg2 (aka args) are arguments provided to the field in the GraphQL query. You supply them from the client.