2

I have built graphql apollo (v4) server by following the docs. I just made the subscription and pubsub work.

However, when I was trying to work on authentication, I realized that my graphql server does not provide context to my resolvers as expected.

Here is my code.

// index.ts
import { ApolloServer } from '@apollo/server';
import { expressMiddleware } from '@apollo/server/express4';
import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer';
import express from 'express';
import { createServer } from 'http';
import { makeExecutableSchema } from '@graphql-tools/schema';
import { WebSocketServer } from 'ws';
import { useServer } from 'graphql-ws/lib/use/ws';
import bodyParser from 'body-parser';
import cors from 'cors';
import { PubSub } from 'graphql-subscriptions';
import { typeDefs, resolvers } from './graphql'

const PORT = 4000;

// Create schema, which will be used separately by ApolloServer and
// the WebSocket server.
const schema = makeExecutableSchema({ typeDefs, resolvers });

// Create an Express app and HTTP server; we will attach the WebSocket
// server and the ApolloServer to this HTTP server.
const app = express();
const httpServer = createServer(app);

// Set up WebSocket server.
const wsServer = new WebSocketServer({
  server: httpServer,
  path: '/graphql',
});

const pubsub = new PubSub();

const getSubscriptionContext = async (ctx: any): Promise<any> => {
  ctx;
  console.log('@@ ctx', ctx);

  // ctx is the graphql-ws Context where connectionParams live
  if (ctx.connectionParams && ctx.connectionParams.session) {
    const { session } = ctx.connectionParams;
    return { session, pubsub };
  }
  // Otherwise let our resolvers know we don't have a current user
  return { session: null, pubsub };
};

const serverCleanup = useServer(
  {
    schema,
    context: (ctx: any) => getSubscriptionContext(ctx)
  },
  wsServer
);

// Set up ApolloServer.
const server = new ApolloServer({
  schema,
  plugins: [
    // Proper shutdown for the HTTP server.
    ApolloServerPluginDrainHttpServer({ httpServer }),

    // Proper shutdown for the WebSocket server.
    {
      async serverWillStart() {
        return {
          async drainServer() {
            await serverCleanup.dispose();
          },
        };
      },
    },
  ],
});

async function init() {
  await server.start();
  app.use('/graphql', cors<cors.CorsRequest>(), bodyParser.json(), expressMiddleware(server));

  // Now that our HTTP server is fully set up, actually listen.
  httpServer.listen(PORT, () => {
    console.log(` Query endpoint ready at http://localhost:${PORT}/graphql`);
    console.log(` Subscription endpoint ready at ws://localhost:${PORT}/graphql`);
  });
};

init();

For some reason, the getSubscriptionContext does not seem to be running at all. When I run query in the browser, I do not see console.log from this function at all. I do not think the server is skipping this block.

Some of the posts have context passed to ApolloServer constructor, but the ApolloServer from @apollo/server (v4) no longer accepts a context parameter.

In the resolver I have:

resolvers: {
    Query: {
      users: (_: any, __: any, context: any) => {
        console.log('@@ context', context);
        return 123;
      }
    }
  } 

this console.log returns an empty object.

@@ context {}

Here's a sample query and mutation:

const user = {
  typeDefs: `
    extend type Query {
      hello: Int
    }

    extend type Mutation {
      hi(name: String): Int
    }
  `,
  resolvers: {
    Query: {
      hello: (_: any, __: any, context: any) => {
        console.log('@@ context', context);
        return 123;
      }
    },
    Mutation: {
      hi: (_: any, args: any, context: any) => {
        console.log('@@', context, args);
        return 123;
      }
    }
  } 
} 

A context is essential for authentication, how can I gain access to it?

Michel Floyd
  • 18,793
  • 4
  • 24
  • 39
  • What queries are you using? – Bergi Oct 24 '22 at 18:27
  • Have you tried using `apollo-server-express` instead of `apollo-server`? [example](https://www.asapdevelopers.com/apollo-integration-with-node-express/) – Michel Floyd Oct 24 '22 at 18:32
  • @Bergi, Thank you for your comment. I have edited my question and query and mutation that I am using are there. as of now, they both are returning nothing – Gwenda Thomas Oct 24 '22 at 18:38
  • @MichelFloyd Thank you for the comment. I have not tried it yet, since I would like to get this apollo-server work. I just finally got subscription work with the frontend. and as much as possible I do not want to rewrite the code unless I really have to. I mean otherwise I would never learn how to figure this out – Gwenda Thomas Oct 24 '22 at 18:40
  • I actually meant the client-side query documents, but either way: it seems you're not actually using a subscription anywhere! So of course the subscription context won't be used. – Bergi Oct 24 '22 at 18:43
  • @Bergi I removed it. because in order to use the subscription, I was going to pass pubsub via context. but as of now, context is not working. So unless I import pubsub into all the files that I want to use, I wont be able to use subscription. If it is working, at least I have to see the pubsub passed through context in the log. Am I wrong? – Gwenda Thomas Oct 24 '22 at 18:58
  • If you just want to get it working with apollo-server then why use express at all? Apollo-server already gives you pub-sub. – Michel Floyd Oct 24 '22 at 19:13
  • @MichelFloyd Do you happen to have any resources that I can take a look at? Because according to the apollo v4 docs, by default subscription is not supported anymore. So I wonder how and why pub-sub is provided by the apollo server... – Gwenda Thomas Oct 24 '22 at 19:19
  • Right you are! Have you tried running their [example on github](https://github.com/apollographql/docs-examples/tree/main/apollo-server/v4/subscriptions-graphql-ws) as is? The [codesandbox.io example](https://codesandbox.io/s/github/apollographql/docs-examples/tree/main/apollo-server/v4/subscriptions-graphql-ws?fontsize=14&hidenavigation=1&initialpath=%2Fgraphql&theme=dark) doesn't appear to run. – Michel Floyd Oct 24 '22 at 19:44
  • @MichelFloyd Thank you for the link!! However, that is exactly where I got the code from. And I added context to `useServer({ schema }, wsServer);` after the schema, but no luck so far. – Gwenda Thomas Oct 24 '22 at 19:49

1 Answers1

3
  1. create a context function near the top of your code
const context = (ctx) => ctx;
  1. Add this function as an argument to your expressMiddleware call:
app.use(
  '/graphql', 
  cors<cors.CorsRequest>(), 
  bodyParser.json(),
  expressMiddleware(server, { context })
);

docs

Michel Floyd
  • 18,793
  • 4
  • 24
  • 39
  • 1
    wow, everything is working now. So I was passing the context in the wrong place. I put my subscription code back and everything is working as I wanted it to. Thank you very much again. You made my day !! Happy Halloween. – Gwenda Thomas Oct 25 '22 at 00:44