Is it possible to define the HTTP headers for the GraphQL Playground that comes with Apollo Server?

pupeno picture pupeno · Jul 12, 2020 · Viewed 12.2k times · Source

I want to define some http headers for the GraphQL Playground, to be enabled by default and/or always. Essentially, I want to add:

"apollographql-client-name": "playground"
"apollographql-client-version": "yada-yada"

to be able to distinguish requests from the playground from any other requests on Apollo Studio. What's the best way?

By GraphQL Playground I refer to the one run by Apollo, the one documented here: https://www.apollographql.com/docs/apollo-server/testing/graphql-playground/

My current ApolloServer config looks something like this:

let apolloServerExpressConfig: ApolloServerExpressConfig = {
  schema: schema,
  playground: {
    settings: {
      "request.credentials": "include",
    },
  },
}

If I add tabs to it in an attempt to define the headers, like this:

let apolloServerExpressConfig: ApolloServerExpressConfig = {
  schema: schema,
  playground: {
    settings: {
      "request.credentials": "include",
    },
    tabs: [{
      headers: {
        "apollographql-client-name": "playground",
        "apollographql-client-version": "yada-yada",
      },
    }],
  },
}

the GraphQL playground no longer restores all tabs with their queries when reloading the page, which is very useful. I think there's some automatic tab management that gets removed as soon as you define tabs. I'm happy to have default headers defined for new tab creation, it's ok if those headers are exposed to the client.

My app already defines header, so, I can differentiate between the app and anything else that queries it, but I want to differentiate between my app, playground and anything else (the latter group should be empty).

Answer

x00 picture x00 · Jul 29, 2020

Update:

https://github.com/apollographql/apollo-server/issues/1982#issuecomment-511765175

use the GraphQL Playground Express middleware directly [...] This would allow you to leverage the Express middleware req object, and set headers accordingly.

Here is a working example:

const app                   = require('express')()
const { ApolloServer, gql } = require('apollo-server-express')

// use this directly
  const expressPlayground   = require('graphql-playground-middleware-express').default

// just some boilerplate to make it runnable
  const typeDefs = gql`type Book { title: String author: String } type Query { books: [Book] }`
  const books = [{ title: 'Harry Potter and the Chamber of Secrets', author: 'J.K. Rowling' }, { title: 'Jurassic Park', author: 'Michael Crichton' }]
  const resolvers = { Query: { books: () => books } }
  const server = new ApolloServer({ typeDefs, resolvers });

//
// the key part {
//
  const headers = JSON.stringify({
    "apollographql-client-name"   : "playground",
    "apollographql-client-version": "yada-yada" ,
  })
  app.get('/graphql', expressPlayground({
    endpoint: `/graphql?headers=${encodeURIComponent(headers)}`,
  }))
  server.applyMiddleware({ app })

//
// }
//

// just some boilerplate to make it runnable
app.listen({ port: 4000 }, () => console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`))

After page reload all tabs with their content are restored.


Answer to the original question:

It's not totally clear what you mean by Apollo Server GraphQL Playground. And what's your use case.

There is a desktop app, a web app, you can include GraphQL Playground as a module into your frontend, or as a middleware for your backend.

For the simplest case: switch to the "HTTP HEADERS" tab, add headers as JSON:

{
  "apollographql-client-name": "playground",
  "apollographql-client-version": "yada-yada",
}

enter image description here

For the case of frontend Playground you can pass tabs with headers property to <Playground/>:

<Playground
  ...
  tabs={[{
    name: 'Tab 1',
    headers: {
      "apollographql-client-name"   : "playground",
      "apollographql-client-version": "yada-yada" ,
    }
    ...
  }]}
/>,

For backend, you can use headers as well:

new ApolloServer({
  ...
  playground: {
    ...
    tabs: [{
      ...
      headers: ...
    }],
  },
})

You can also

distinguish requests from the playground from requests from the actual apps

by going the opposite way: add extra headers to you actual apps.