Skip to content
This repository was archived by the owner on Mar 20, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"testonly": "mocha $npm_package_options_mocha",
"lint": "eslint src",
"check": "flow check",
"build": "rm -rf dist/* && babel src --ignore __tests__ --out-dir dist",
"build": "rm -rf dist/* && babel src --ignore __tests__ --out-dir dist && cp -r vendor dist/",
"watch": "node resources/watch.js",
"cover": "babel-node node_modules/.bin/isparta cover --root src --report html node_modules/.bin/_mocha -- $npm_package_options_mocha",
"cover:lcov": "babel-node node_modules/.bin/isparta cover --root src --report lcovonly node_modules/.bin/_mocha -- $npm_package_options_mocha",
Expand Down
35 changes: 27 additions & 8 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/

import path from 'path';
import accepts from 'accepts';
import {
Source,
Expand All @@ -30,10 +31,12 @@ import type {
GraphQLSchema
} from 'graphql';
import type { Response } from 'express';
import express from 'express';

export type Request = {
method: string;
url: string;
baseUrl: string,
body: mixed;
headers: {[header: string]: mixed};
pipe<T>(stream: T): T;
Expand Down Expand Up @@ -99,7 +102,7 @@ export type OptionsData = {
/**
* A boolean to optionally enable GraphiQL mode.
*/
graphiql?: ?boolean,
graphiql?: ?(boolean | string),
};

/**
Expand Down Expand Up @@ -128,18 +131,28 @@ export type RequestInfo = {
};

type Middleware = (request: Request, response: Response) => Promise<void>;
type Router = {
use: (route: string, middleware: Middleware) => void
};

/**
* Middleware for express; takes an options object or function as input to
* configure behavior, and returns an express middleware.
* An express router; takes an options object or function as input to
* configure behavior, and returns an express router that has been
* loaded with the middleware function and an endpoint to serve local
* files.
*/
module.exports = graphqlHTTP;
function graphqlHTTP(options: Options): Middleware {
function graphqlHTTP(options: Options): Router {
if (!options) {
throw new Error('GraphQL middleware requires options.');
}

return (request: Request, response: Response) => {
const router = new express.Router();

// Set up the static files to serve
router.use('/vendor', express.static(path.join(__dirname, 'vendor/')));

router.use('/', (request: Request, response: Response) => {
// Higher scoped variables are referred to at various stages in the
// asynchronous state machine below.
let schema;
Expand Down Expand Up @@ -209,7 +222,9 @@ function graphqlHTTP(options: Options): Middleware {
query = params.query;
variables = params.variables;
operationName = params.operationName;
showGraphiQL = graphiql && canDisplayGraphiQL(request, params);
showGraphiQL = graphiql &&
canDisplayGraphiQL(request, params) &&
graphiql;

// If there is no query, but GraphiQL will be displayed, do not produce
// a result, otherwise return a 400: Bad Request.
Expand Down Expand Up @@ -312,9 +327,11 @@ function graphqlHTTP(options: Options): Middleware {
}
// If allowed to show GraphiQL, present it instead of JSON.
if (showGraphiQL) {
const baseURLWithTrailingSlash = request.baseUrl.replace(/\/?$/, '/');
const payload = renderGraphiQL({
query, variables,
operationName, result
operationName, result,
showGraphiQL, baseURLWithTrailingSlash
});
response.setHeader('Content-Type', 'text/html; charset=utf-8');
sendResponse(response, payload);
Expand All @@ -325,7 +342,9 @@ function graphqlHTTP(options: Options): Middleware {
sendResponse(response, payload);
}
});
};
});

return router;
}

export type GraphQLParams = {
Expand Down
44 changes: 38 additions & 6 deletions src/renderGraphiQL.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ type GraphiQLData = {
query: ?string,
variables: ?{[name: string]: mixed},
operationName: ?string,
result?: mixed
result?: mixed,
showGraphiQL?: ?(boolean | string),
baseURLWithTrailingSlash: string
};

// Current latest version of GraphiQL.
Expand All @@ -37,6 +39,39 @@ export function renderGraphiQL(data: GraphiQLData): string {
const resultString =
data.result ? JSON.stringify(data.result, null, 2) : null;
const operationName = data.operationName;
const showGraphiQL = data.showGraphiQL;
const path = data.baseURLWithTrailingSlash;

let cssUrl = null;
let scriptUrls = null;

switch (showGraphiQL) {
case 'local' :
scriptUrls = [
`${path}vendor/fetch.min-0.9.0.js`,
`${path}vendor/react.min-15.4.2.js`,
`${path}vendor/react-dom.min-15.4.2.js`,
`${path}vendor/graphiql.min-${GRAPHIQL_VERSION}.js`
];
cssUrl = `${path}vendor/graphiql-${GRAPHIQL_VERSION}.css`;
break;


case 'cdn' :
case true :
scriptUrls = [
'//cdn.jsdelivr.net/fetch/0.9.0/fetch.min.js',
'//cdn.jsdelivr.net/react/15.4.2/react.min.js',
'//cdn.jsdelivr.net/react/15.4.2/react-dom.min.js',
`//cdn.jsdelivr.net/graphiql/${GRAPHIQL_VERSION}/graphiql.min.js`
];
cssUrl = `//cdn.jsdelivr.net/graphiql/${GRAPHIQL_VERSION}/graphiql.css`;
break;


default :
throw new Error('showGraphiQL must be a boolean, "cdn" or "local".');
}

/* eslint-disable max-len */
return `<!--
Expand All @@ -61,11 +96,8 @@ add "&raw" to the end of the URL within a browser.
width: 100%;
}
</style>
<link href="//cdn.jsdelivr.net/graphiql/${GRAPHIQL_VERSION}/graphiql.css" rel="stylesheet" />
<script src="//cdn.jsdelivr.net/fetch/0.9.0/fetch.min.js"></script>
<script src="//cdn.jsdelivr.net/react/15.4.2/react.min.js"></script>
<script src="//cdn.jsdelivr.net/react/15.4.2/react-dom.min.js"></script>
<script src="//cdn.jsdelivr.net/graphiql/${GRAPHIQL_VERSION}/graphiql.min.js"></script>
<link href="${cssUrl}" rel="stylesheet" />
${scriptUrls.map(url => `<script src="${url}"></script>`).join('\n ')}
</head>
<body>
<script>
Expand Down
1 change: 1 addition & 0 deletions vendor/fetch.min-0.9.0.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading