5
votes

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

2

2 Answers

5
votes

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.

0
votes

Apollo-server-plugin-http-headers

Allows you to set HTTP Headers and Cookies easily in your resolvers. This is especially useful in apollo-server-lambda, because you don't have any other options there to set headers or cookies.

The way it works is simple: you put an array for cookies and an array for headers in your context; you can then access them in your resolvers (and therefore add, alter or delete headers and cookies). Before your request is sent to the client this plugin loops through the arrays and adds every item to the HTTP response. The logic is very easy, actually the documentation is way longer than the source code.

Usage - Headers

Set a header in a resolver:

context.setHeaders.push({ key: "headername", value: "headercontent" });

Complete example:

const resolvers = {
    Query: {
        hello: async (parent, args, context, info) => {
            context.setHeaders.push({ key: "X-TEST-ONE", value: "abc" });
            context.setHeaders.push({ key: "X-TEST-TWO", value: "def" });
            return "Hello world!";
        }
    }
};