Graphql-playground: Error: Can't set headers after they are sent.

Created on 5 Feb 2018  路  10Comments  路  Source: graphql/graphql-playground

This issue pertains to the following package(s):

  • [/] GraphQL Playground
  • [/] GraphQL Playground Express Middleware

What OS and OS version are you experiencing the issue(s) on?

Ubuntu 16.04

What version of graphql-playground(-electron/-middleware) are you experiencing the issue(s) on?

    "apollo-server-express": "^1.3.2",
    "express": "^4.16.2",
    "express-session": "^1.15.6",
    "express-validator": "^4.3.0",
    "graphql": "0.11.7",
    "graphql-playground-middleware-express": "^1.5.6",
    "graphql-subscriptions": "^0.5.6",
    "graphql-tools": "^2.18.0",

What is the expected behavior?

Should show the playground like the screenshot in document when accessed via browser

What is the actual behavior?

GET /playground 500 0.150 ms - -
Error: Can't set headers after they are sent.
    at validateHeader (_http_outgoing.js:494:11)
    at ServerResponse.setHeader (_http_outgoing.js:501:3)
    at ServerResponse.header (/home/arvi/Documents/Projects/myapp/node_modules/express/lib/response.js:767:10)
    at ServerResponse.send (/home/arvi/Documents/Projects/myapp/node_modules/express/lib/response.js:170:12)
    at ServerResponse.json (/home/arvi/Documents/Projects/myapp/node_modules/express/lib/response.js:267:15)
    at /home/arvi/Documents/Projects/myapp/app/index.js:99:7
    at Layer.handle_error (/home/arvi/Documents/Projects/myapp/node_modules/express/lib/router/layer.js:71:5)
    at trim_prefix (/home/arvi/Documents/Projects/myapp/node_modules/express/lib/router/index.js:315:13)
    at /home/arvi/Documents/Projects/myapp/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/home/arvi/Documents/Projects/myapp/node_modules/express/lib/router/index.js:335:12)
    at next (/home/arvi/Documents/Projects/myapp/node_modules/express/lib/router/index.js:275:10)
    at Layer.handle_error (/home/arvi/Documents/Projects/myapp/node_modules/express/lib/router/layer.js:67:12)
    at trim_prefix (/home/arvi/Documents/Projects/myapp/node_modules/express/lib/router/index.js:315:13)
    at /home/arvi/Documents/Projects/myapp/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/home/arvi/Documents/Projects/myapp/node_modules/express/lib/router/index.js:335:12)
    at next (/home/arvi/Documents/Projects/myapp/node_modules/express/lib/router/index.js:275:10)
    at Layer.handle [as handle_request] (/home/arvi/Documents/Projects/myapp/node_modules/express/lib/router/layer.js:97:5)
    at trim_prefix (/home/arvi/Documents/Projects/myapp/node_modules/express/lib/router/index.js:317:13)
    at /home/arvi/Documents/Projects/myapp/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/home/arvi/Documents/Projects/myapp/node_modules/express/lib/router/index.js:335:12)
    at next (/home/arvi/Documents/Projects/myapp/node_modules/express/lib/router/index.js:275:10)
    at session (/home/arvi/Documents/Projects/myapp/node_modules/express-session/index.js:454:7)

What steps may we take to reproduce the behavior?

I tried to follow this, I don't know what I missed. https://github.com/graphcool/graphql-playground/blob/master/packages/graphql-playground-middleware-express/examples/basic/index.js#L27

HERE IS MY CODE

import express from 'express';
import cors from 'cors';
import cookieParser from 'cookie-parser';
import bodyParser from 'body-parser';
import expressSession from 'express-session';
import connectMongo from 'connect-mongo';
import http from 'http';
import compression from 'compression';
import { graphqlExpress } from 'apollo-server-express';
import expressPlayground from 'graphql-playground-middleware-express';
import config from './../config';
import db from './../config/db';
import routes from './routes/index.route';
import schema from './graphql/src/schema';


const MongoStore = connectMongo(expressSession);
const app = express();


app.use(compression());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cookieParser());

// graphql endpoint; set tracing and cache control to ture
app.use(
  '/graphql',
  bodyParser.json(),
  graphqlExpress({ schema, tracing: true, cacheControl: true }),
);

// graphiql, visual editor for queries
app.get('/playground', expressPlayground({ endpoint: '/graphql' }));

// setup session handling options
const session = expressSession({
  secret: config.sessionStore.secret,
  store: new MongoStore({ mongooseConnection: db.connection }),
  resave: false,
  saveUninitialized: false,
});
app.use(session);

app.use(cors());

// set routes for API
app.use('/api', routes);

const server = http.createServer(app);
server.listen(config.site.port, (err) => {
    if (err) {
      throw err;
    }

    DEBUG(`LISTENING: ${config.site.protocol}://${config.site.host}:${config.site.port}...`);
  });
bu2-confirmed

Most helpful comment

Same problem with the latest graphql-playground-middleware-express version 1.7.0. If you are using Apollo Server v2 with apollo-server-express, you can apply the trick by @vizo like so

new ApolloServer({ typeDefs, Resolvers }).applyMiddleware({ app })
app.use('/graphql', () => {})

All 10 comments

I am also getting this error.

@adamjking3 @timsuchanek Can't set headers after they are sent still persists even on my iMac High Sierra 2009, not just Ubuntu machine but somehow I was now able to show the playground from the url as compared to nothing at all before. It turns out that it has conflict with compression middleware. I put the compression as the very last middleware and put the app.get('/gq', expressPlayground({ endpoint: '/graphql' })); right after initiating the app variable.

In Playground Express Middleware https://github.com/graphcool/graphql-playground/blob/a5a59707e59dee92576ce91b213f8655bce28b2a/packages/graphql-playground-middleware-express/src/index.ts#L32
res.next() should be removed.

As a workaround you can mount middleware like this:
app.get('/graphiql', graphqlPlaygroundMiddleware({ endpoint: '/graphql' }), () => {})

Same problem with the latest graphql-playground-middleware-express version 1.7.0. If you are using Apollo Server v2 with apollo-server-express, you can apply the trick by @vizo like so

new ApolloServer({ typeDefs, Resolvers }).applyMiddleware({ app })
app.use('/graphql', () => {})

@alex996 I guess you meant @vizo :) Just to give credit to whom credit is due :)

Thanks @vizo && @alex996 馃憤

My Solution was

app = express();
app.use('/graphql', expressPlayground({ endpoint: '/graphql' }));
app.get('/graphql', function(req, res) {
  res.end('');
});

@xelaz Your fix helped me, but fwiw you only need expressPlayground on get, so you could just do:

app.get('/graphql', expressPlayground({ endpoint: '/graphql' }), function(req, res) {
  res.end('');
});

Also, here's hoping my fix gets merged

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nicolas-besnard picture nicolas-besnard  路  22Comments

schickling picture schickling  路  52Comments

Deepaknathtiwari picture Deepaknathtiwari  路  11Comments

grahamb picture grahamb  路  20Comments

marktani picture marktani  路  13Comments