graphile / crystal

🔮 Graphile's Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!
https://graphile.org/
Other
12.55k stars 569 forks source link

Bundle `graphql-voyager` in GraphiQL #1095

Open marshall007 opened 5 years ago

marshall007 commented 5 years ago

I'm submitting a ...

It is fairly trivial to expose graphql-voyager yourself if you are already consuming postgraphile as a library. Doing so is roughly as easy as:

import * as express from 'express';
import { express as voyagerMiddleware } from 'graphql-voyager/middleware';
import { postgraphile } from 'postgraphile';

const app = express();

app.use(postgraphile(PG_POOL, PG_SCHEMA, graphileConfig));
app.use('/voyager', voyagerMiddleware({
  endpointUrl: `${graphileConfig.externalUrlBase || ''}/graphql`,
  displayOptions: {
    hideRoot: true,
    skipDeprecated: true,
    skipRelay: true,
  },
}));

app.listen(PORT, () => {
  console.log(`Listening on localhost:${PORT}`);
});

It would be nice to have Voyager bundled for a couple reasons, namely:

  1. easier for CLI users to explore their schema graphically
  2. possibility for tighter integration with our custom GraphiQL interface (i.e. deep linking, which is not yet supported by Voyager)
  3. could be loaded at the same /graphiql endpoint
marshall007 commented 5 years ago

Related to #1074 in that Voyager is probably closer to what you'd want to expose to end-users instead of the entire GraphiQL console.

benjie commented 5 years ago

I definitely don't want to bundle more stuff inside PostGraphile; however I've planned to write a voyager server plugin for quite a while just haven't got around to it. To do so, you should only need to implement one hook, against this:

https://github.com/graphile/postgraphile/blob/83024fbba8f20b123bcec6b5f3543f0500bfd011/src/postgraphile/http/createPostGraphileHttpRequestHandler.ts#L435-L446

Something like:

const { express: makeVoyagerMiddleware } = require('graphql-voyager/middleware');

let voyagerMiddleware;
module.exports = {
  // Use this hook for access to the options, so we know where the GraphQL endpoint is:
  'postgraphile:options': (options) => {
    voyagerMiddleware = makeVoyagerMiddleware({
      endpointUrl: `${options.externalUrlBase || ''}/${options.graphqlRoute}`,
      displayOptions: {
        hideRoot: true,
        skipDeprecated: true,
        skipRelay: true,
      },
    });
    return options;
  },

  // Use this hook to pass over to the voyager middleware if the request matches
  'postgraphile:http:handler': (incomingReq, { options, res, next }) => {
    if (!incomingReq.match(/^\/voyager(\?|$)/)) return incomingReq;
    middleware(incomingReq, res, next);
    return null;
  }
};

This was written direct into GitHub editor, so it's probably going to need some fixes.