Skip to content

Commit 9784a6a

Browse files
committed
feat: Upgrade to latest webfunc and make it compatible with express + add Facebook patent
1 parent a65c460 commit 9784a6a

File tree

5 files changed

+83
-218
lines changed

5 files changed

+83
-218
lines changed

PATENT

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Additional Grant of Patent Rights Version 2
2+
3+
"Software" means the GraphQL software distributed by Facebook, Inc.
4+
5+
Facebook, Inc. (“Facebook”) hereby grants to each recipient of the Software (“you”) a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (subject to the termination provision below) license under any Necessary Claims, to make, have made, use, sell, offer to sell, import, and otherwise transfer the Software. For avoidance of doubt, no license is granted under Facebook’s rights in any patent claims that are infringed by (i) modifications to the Software made by you or any third party or (ii) the Software in combination with any software or other technology.
6+
7+
The license granted hereunder will terminate, automatically and without notice, if you (or any of your subsidiaries, corporate affiliates or agents) initiate directly or indirectly, or take a direct financial interest in, any Patent Assertion: (i) against Facebook or any of its subsidiaries or corporate affiliates, (ii) against any party if such Patent Assertion arises in whole or in part from any software, technology, product or service of Facebook or any of its subsidiaries or corporate affiliates, or (iii) against any party relating to the Software. Notwithstanding the foregoing, if Facebook or any of its subsidiaries or corporate affiliates files a lawsuit alleging patent infringement against you in the first instance, and you respond by filing a patent infringement counterclaim in that lawsuit against that party that is unrelated to the Software, the license granted hereunder will not terminate under section (i) of this paragraph due to such counterclaim.
8+
9+
A “Necessary Claim” is a claim of a patent owned by Facebook that is necessarily infringed by the Software standing alone.
10+
11+
A “Patent Assertion” is any lawsuit or other action alleging direct, indirect, or contributory infringement or inducement to infringe any patent, including a cross-claim or counterclaim.

package.json

+14-13
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
"main": "src/index.js",
99
"scripts": {
1010
"test": "mocha",
11-
"eslint": "eslint src/",
12-
"release": "standard-version --prerelease alpha"
11+
"eslint": "eslint src/ --fix",
12+
"release": "standard-version --prerelease alpha",
13+
"release:minor": "standard-version --release-as minor"
1314
},
1415
"repository": {
1516
"type": "git",
@@ -29,22 +30,22 @@
2930
},
3031
"homepage": "https://github.com/nicolasdao/google-graphql-functions#readme",
3132
"dependencies": {
32-
"accepts": "^1.3.3",
33-
"content-type": "^1.0.2",
34-
"graphql": "^0.9.3",
35-
"graphql-tools": "^1.2.2",
36-
"http-errors": "^1.6.1",
37-
"querystring": "^0.2.0",
38-
"raw-body": "^2.2.0",
39-
"standard-version": "^4.2.0",
40-
"url": "^0.11.0",
41-
"webfunc": "^0.8.0-alpha.2"
33+
"accepts": "1.3.3",
34+
"content-type": "1.0.2",
35+
"graphql": "0.9.3",
36+
"graphql-tools": "1.2.2",
37+
"http-errors": "1.6.1",
38+
"querystring": "0.2.0",
39+
"raw-body": "2.2.0",
40+
"standard-version": "4.2.0",
41+
"url": "0.11.0"
4242
},
4343
"devDependencies": {
4444
"chai": "^4.1.0",
4545
"eslint": "^4.1.1",
4646
"mocha": "^3.4.2",
4747
"node-mocks-http": "^1.6.4",
48-
"standard-version": "^4.2.0"
48+
"standard-version": "^4.2.0",
49+
"webfunc": "^0.10.0-alpha.1"
4950
}
5051
}

src/index.js

+13-32
Original file line numberDiff line numberDiff line change
@@ -19,47 +19,28 @@
1919

2020
const accepts = require('accepts')
2121
const graphql = require('graphql')
22-
const { routing, HttpHandler } = require('webfunc')
2322
const httpError = require('http-errors')
2423
const url = require('url')
25-
const path = require('path')
2624

2725
const parseBody = require('./parseBody')
2826
const renderGraphiQL = require('./renderGraphiQL')
2927

30-
class GraphQlHandler extends HttpHandler {
31-
constructor(options, control) { super(options, control) }
32-
get id() { return 'graphql' }
28+
const graphqlHandler = options => {
29+
if (!options)
30+
throw new Error('Missing required argument. A graphql handler must accept an \'options\' object')
3331

34-
process(req, res, params, route) {
35-
return super.control(req, res, { request: params, get options() { return super.options }, err: null })
36-
.then(graphQlOptions => {
37-
const options = graphQlOptions || super.options
38-
const httpEndpoint = ((req._parsedUrl || {}).pathname || '/').toLowerCase()
39-
const endpoint = route ? ((routing.matchRoute(httpEndpoint, route) || {}).match || '/') : '/'
40-
if (!res.headersSent) {
41-
if (!options)
42-
throw httpError(500, 'GraphQL middleware requires getOptions.')
43-
else {
44-
const optionsWithNewGraphiqlUri = mergeGraphqlOptionsWithEndpoint(options, endpoint)
45-
const httpHandler = graphqlHTTP(optionsWithNewGraphiqlUri)
46-
if (!httpHandler)
47-
throw httpError(500, 'GraphQL middleware requires a valid \'getOptions\' argument.')
48-
return httpHandler(req, res)
49-
}
50-
}
51-
})
32+
return (req, res, next) => {
33+
if (!res.headersSent) {
34+
const httpHandler = graphqlHTTP(options)
35+
if (!httpHandler)
36+
throw httpError(500, 'GraphQL middleware requires a valid \'getOptions\' argument.')
37+
return httpHandler(req, res).then(() => next())
38+
}
39+
else
40+
next()
5241
}
5342
}
5443

55-
/*eslint-disable */
56-
const pathJoin = (path1, path2) => process.platform === 'win32' ? path.join(path1, path2).replace(/\\/g,'/') : path.join(path1, path2)
57-
/*eslint-enable */
58-
59-
const mergeGraphqlOptionsWithEndpoint = (graphqlOptions = {}, endpointPath = '/') => graphqlOptions.endpointURL
60-
? Object.assign({}, graphqlOptions, { endpointURL: pathJoin(endpointPath, graphqlOptions.endpointURL) })
61-
: graphqlOptions
62-
6344
function graphqlHTTP(options) {
6445
if (!options) {
6546
throw new Error('GraphQL middleware requires options.')
@@ -334,5 +315,5 @@ function sendResponse(response, data) {
334315
}
335316

336317
module.exports = {
337-
HttpHandler: GraphQlHandler
318+
graphqlHandler
338319
}

src/renderGraphiQL.js

+14-127
Original file line numberDiff line numberDiff line change
@@ -17,147 +17,34 @@
1717
* of patent rights can be found in the PATENTS file in the same directory.
1818
*/
1919

20+
'use strict'
21+
22+
Object.defineProperty(exports, '__esModule', {
23+
value: true
24+
})
25+
2026
// Current latest version of GraphiQL.
21-
const GRAPHIQL_VERSION = '0.9.3'
27+
var GRAPHIQL_VERSION = '0.11.2'
2228

2329
// Ensures string values are safe to be used within a <script> tag.
30+
2431
function safeSerialize(data) {
2532
return data ? JSON.stringify(data).replace(/\//g, '\\/') : 'undefined'
2633
}
2734

2835
/**
29-
* When the server receives a request which does not Accept JSON, but does
36+
* When express-graphql receives a request which does not Accept JSON, but does
3037
* Accept HTML, it may present GraphiQL, the in-browser GraphQL explorer IDE.
3138
*
3239
* When shown, it will be pre-populated with the result of having executed the
3340
* requested query.
3441
*/
3542
module.exports = function renderGraphiQL(data) {
36-
const queryString = data.query
37-
const variablesString = data.variables ? JSON.stringify(data.variables, null, 2) : null
38-
const resultString = data.result ? JSON.stringify(data.result, null, 2) : null
39-
const operationName = data.operationName
43+
var queryString = data.query
44+
var variablesString = data.variables ? JSON.stringify(data.variables, null, 2) : null
45+
var resultString = data.result ? JSON.stringify(data.result, null, 2) : null
46+
var operationName = data.operationName
4047

4148
/* eslint-disable max-len */
42-
return `<!--
43-
The request to this GraphQL server provided the header "Accept: text/html"
44-
and as a result has been presented GraphiQL - an in-browser IDE for
45-
exploring GraphQL.
46-
47-
If you wish to receive JSON, provide the header "Accept: application/json" or
48-
add "&raw" to the end of the URL within a browser.
49-
-->
50-
<!DOCTYPE html>
51-
<html>
52-
<head>
53-
<meta charset="utf-8" />
54-
<title>GraphiQL</title>
55-
<meta name="robots" content="noindex" />
56-
<style>
57-
html, body {
58-
height: 100%;
59-
margin: 0;
60-
overflow: hidden;
61-
width: 100%;
62-
}
63-
</style>
64-
<link href="//cdn.jsdelivr.net/graphiql/${GRAPHIQL_VERSION}/graphiql.css" rel="stylesheet" />
65-
<script src="//cdn.jsdelivr.net/fetch/0.9.0/fetch.min.js"></script>
66-
<script src="//cdn.jsdelivr.net/react/15.4.2/react.min.js"></script>
67-
<script src="//cdn.jsdelivr.net/react/15.4.2/react-dom.min.js"></script>
68-
<script src="//cdn.jsdelivr.net/graphiql/${GRAPHIQL_VERSION}/graphiql.min.js"></script>
69-
</head>
70-
<body>
71-
<script>
72-
// Collect the URL parameters
73-
var parameters = {};
74-
window.location.search.substr(1).split('&').forEach(function (entry) {
75-
var eq = entry.indexOf('=');
76-
if (eq >= 0) {
77-
parameters[decodeURIComponent(entry.slice(0, eq))] =
78-
decodeURIComponent(entry.slice(eq + 1));
79-
}
80-
});
81-
82-
// Produce a Location query string from a parameter object.
83-
function locationQuery(params) {
84-
return '?' + Object.keys(params).map(function (key) {
85-
return encodeURIComponent(key) + '=' +
86-
encodeURIComponent(params[key]);
87-
}).join('&');
88-
}
89-
90-
// Derive a fetch URL from the current URL, sans the GraphQL parameters.
91-
var graphqlParamNames = {
92-
query: true,
93-
variables: true,
94-
operationName: true
95-
};
96-
97-
var otherParams = {};
98-
for (var k in parameters) {
99-
if (parameters.hasOwnProperty(k) && graphqlParamNames[k] !== true) {
100-
otherParams[k] = parameters[k];
101-
}
102-
}
103-
var fetchURL = locationQuery(otherParams);
104-
// Defines a GraphQL fetcher using the fetch API.
105-
function graphQLFetcher(graphQLParams) {
106-
return fetch(fetchURL, {
107-
method: 'post',
108-
headers: {
109-
'Accept': 'application/json',
110-
'Content-Type': 'application/json'
111-
},
112-
body: JSON.stringify(graphQLParams),
113-
credentials: 'include',
114-
}).then(function (response) {
115-
return response.text();
116-
}).then(function (responseBody) {
117-
try {
118-
return JSON.parse(responseBody);
119-
} catch (error) {
120-
console.log(error);
121-
return responseBody;
122-
}
123-
});
124-
}
125-
// When the query and variables string is edited, update the URL bar so
126-
// that it can be easily shared.
127-
function onEditQuery(newQuery) {
128-
parameters.query = newQuery;
129-
updateURL();
130-
}
131-
132-
function onEditVariables(newVariables) {
133-
parameters.variables = newVariables;
134-
updateURL();
135-
}
136-
137-
function onEditOperationName(newOperationName) {
138-
parameters.operationName = newOperationName;
139-
updateURL();
140-
}
141-
142-
function updateURL() {
143-
history.replaceState(null, null, locationQuery(parameters));
144-
}
145-
146-
// Render <GraphiQL /> into the body.
147-
ReactDOM.render(
148-
React.createElement(GraphiQL, {
149-
fetcher: graphQLFetcher,
150-
onEditQuery: onEditQuery,
151-
onEditVariables: onEditVariables,
152-
onEditOperationName: onEditOperationName,
153-
query: ${safeSerialize(queryString)},
154-
response: ${safeSerialize(resultString)},
155-
variables: ${safeSerialize(variablesString)},
156-
operationName: ${safeSerialize(operationName)},
157-
}),
158-
document.body
159-
);
160-
</script>
161-
</body>
162-
</html>`
49+
return '<!--\nThe request to this GraphQL server provided the header "Accept: text/html"\nand as a result has been presented GraphiQL - an in-browser IDE for\nexploring GraphQL.\n\nIf you wish to receive JSON, provide the header "Accept: application/json" or\nadd "&raw" to the end of the URL within a browser.\n-->\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset="utf-8" />\n <title>GraphiQL</title>\n <meta name="robots" content="noindex" />\n <style>\n html, body {\n height: 100%;\n margin: 0;\n overflow: hidden;\n width: 100%;\n }\n </style>\n <link href="//cdn.jsdelivr.net/npm/graphiql@' + GRAPHIQL_VERSION + '/graphiql.css" rel="stylesheet" />\n <script src="//cdn.jsdelivr.net/fetch/0.9.0/fetch.min.js"></script>\n <script src="//cdn.jsdelivr.net/react/15.4.2/react.min.js"></script>\n <script src="//cdn.jsdelivr.net/react/15.4.2/react-dom.min.js"></script>\n <script src="//cdn.jsdelivr.net/npm/graphiql@' + GRAPHIQL_VERSION + '/graphiql.min.js"></script>\n</head>\n<body>\n <script>\n // Collect the URL parameters\n var parameters = {};\n window.location.search.substr(1).split(\'&\').forEach(function (entry) {\n var eq = entry.indexOf(\'=\');\n if (eq >= 0) {\n parameters[decodeURIComponent(entry.slice(0, eq))] =\n decodeURIComponent(entry.slice(eq + 1));\n }\n });\n\n // Produce a Location query string from a parameter object.\n function locationQuery(params) {\n return \'?\' + Object.keys(params).filter(function (key) {\n return Boolean(params[key]);\n }).map(function (key) {\n return encodeURIComponent(key) + \'=\' +\n encodeURIComponent(params[key]);\n }).join(\'&\');\n }\n\n // Derive a fetch URL from the current URL, sans the GraphQL parameters.\n var graphqlParamNames = {\n query: true,\n variables: true,\n operationName: true\n };\n\n var otherParams = {};\n for (var k in parameters) {\n if (parameters.hasOwnProperty(k) && graphqlParamNames[k] !== true) {\n otherParams[k] = parameters[k];\n }\n }\n var fetchURL = locationQuery(otherParams);\n\n // Defines a GraphQL fetcher using the fetch API.\n function graphQLFetcher(graphQLParams) {\n return fetch(fetchURL, {\n method: \'post\',\n headers: {\n \'Accept\': \'application/json\',\n \'Content-Type\': \'application/json\'\n },\n body: JSON.stringify(graphQLParams),\n credentials: \'include\',\n }).then(function (response) {\n return response.text();\n }).then(function (responseBody) {\n try {\n return JSON.parse(responseBody);\n } catch (error) {\n return responseBody;\n }\n });\n }\n\n // When the query and variables string is edited, update the URL bar so\n // that it can be easily shared.\n function onEditQuery(newQuery) {\n parameters.query = newQuery;\n updateURL();\n }\n\n function onEditVariables(newVariables) {\n parameters.variables = newVariables;\n updateURL();\n }\n\n function onEditOperationName(newOperationName) {\n parameters.operationName = newOperationName;\n updateURL();\n }\n\n function updateURL() {\n history.replaceState(null, null, locationQuery(parameters));\n }\n\n // Render <GraphiQL /> into the body.\n ReactDOM.render(\n React.createElement(GraphiQL, {\n fetcher: graphQLFetcher,\n onEditQuery: onEditQuery,\n onEditVariables: onEditVariables,\n onEditOperationName: onEditOperationName,\n query: ' + safeSerialize(queryString) + ',\n response: ' + safeSerialize(resultString) + ',\n variables: ' + safeSerialize(variablesString) + ',\n operationName: ' + safeSerialize(operationName) + ',\n }),\n document.body\n );\n </script>\n</body>\n</html>'
16350
}

0 commit comments

Comments
 (0)