apollo-server: Can't set GraphQL Playground options like preset auth headers for tabs dynamically

Back when I used GraphiQL, it was just a simple express middleware I could wrap in whatever code I wanted, so I would get a username query parameter and generate a token for it to pass as the authorization header to GraphiQL.

But AFAIK from the Apollo Server docs and reading the code, I’m only able to provide static GraphQL playground config at construction time, so there’s no way to do this.

Any real-world dev team isn’t going to want to have to set the authorization header in GraphQL Playground by hand. I ended up copying out the code that calls renderPlaygroundPage so that when I navigate to /graphql?username=jimbob it automatically puts in the authorization header for jimbob. Had to put this into my own middleware that bypasses ApolloServer.applyMiddleware entirely.

I’m kind of angry about the hassles Apollo Server 2 has created. In the process of trying to make it easier for novice users to set up, you’ve made it harder to customize. The dumb use case is easier but for any real-world use case there’s just one more layer of indirection (the ApolloServer class) to dig through the code for to figure out how to pass options through to the low-level stuff like express middleware and the subscription server.

Please bring back documentation for the piecemeal approach that relies on calling graphqlExpress etc. directly instead of creating an ApolloServer class.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 20
  • Comments: 21 (9 by maintainers)

Most upvoted comments

@rgoldfinger In order for what you have to work you have to import defaultPlaygroundOptions from apollo-server-express (or whatever integration you happen to be using). I assume you’re doing that, but for the benefit of others:

import { defaultPlaygroundOptions } from 'apollo-server-express';

I’m also doing an additional spread to make sure I’m not missing anything:

app.get('/graphql', (req, res, next) => {
  const headers = JSON.stringify({
    'X-CSRF-Token': req.csrfToken(),
  });
  expressPlayground({
    ...defaultPlaygroundOptions,
    endpoint: `/graphql?headers=${encodeURIComponent(headers)}`,
    settings: {
      ...defaultPlaygroundOptions.settings,
      'request.credentials': 'same-origin',
    },
  })(req, res, next);
});

I also had to use app.get for the playground middleware instead of app.use and explicitly place it before server.applyMiddleware({ app }) (I only use POST for queries) in order to get the playground and apollo to work together on the same endpoint.

With all of that out of the way, I’d like to point out how simple this is with Graph_i_QL:

app.use('/graphiql', graphiqlExpress(req => ({
  endpointURL: '/graphql',
  passHeader: `'X-CSRF-Token': '${req.csrfToken()}',`,
})));

If we could restore that simplicity here that would be great. I just got done spending several hours getting basic security to work.

I believe this one should be reopened, as it’s quite frustrating.

There is no option to set the default headers for the playground, based on the currently logged-in user.

GraphQL Playground should support the setting of tabs to any valid Tabs[] setting, which should include the ability to set options like endpoint, variables, headers, etc.:

From the GraphQL Playground documentation:

  • tabs Tab[] - An array of tabs.
interface Tab {
	endpoint: string
	query: string
	name?: string
	variables?: string
	responses?: string[]
	headers?: { [key: string]: string }
}

And this should be possible to set within the Apollo Server constructor playground options. Please report back with a runnable reproduction (e.g. CodeSandbox, Glitch or a clone-able GitHub repository which can be npm started) if this is not the case on the latest version of Apollo Server, and we’ll be happy to investigate further. Thanks!

I have the same problem. I solved it by using the graphql playground directly as a middleware:

  import expressPlayground from 'graphql-playground-middleware-express';


  app.use(
    '/graphql',
    (req: express.Request, res: express.Response, next: express.NextFunction) => {
      expressPlayground({
        endpoint: `/graphql?headers=${encodeURIComponent(
          JSON.stringify({
            'x-csrf-token': `${req.cookies.csrf_token}`,
          }),
        )}`,
        settings: {
          ...defaultPlaygroundOptions.settings,
          'request.credentials': 'include',
        },
      })(req, res, next);
    },
  );

And disabled the playground in ApolloServer:

  const apollo = new ApolloServer({
    schema,
    introspection: true,
    playground: false,
    ...
  });

It would be really nice to do this directly in ApolloServer, as lpellegr suggested.

@rgoldfinger @knpwrs Thank you both guys! Your solution works seamlessly! This should be definitely fixed in apollo-server on its own.

Like, the documentation should start out by saying “you’ll probably need to turn off the built-in playground and replace it with your own middleware so you can customize the headers etc.” and then link to how to do that

@abernix - I think you are missing the point. We have no access to the request object in the playground settings, therefore, we cannot programmatically set the headers… Therefore, this isn’t a solution.