koa-graphql
Advanced tools
Comparing version 0.4.0 to 0.4.1
@@ -14,6 +14,12 @@ 'use strict'; | ||
var _graphql = require('graphql'); | ||
var _graphqlError = require('graphql/error'); | ||
var _graphqlExecution = require('graphql/execution'); | ||
var _graphqlLanguage = require('graphql/language'); | ||
var _graphqlValidation = require('graphql/validation'); | ||
var _graphqlUtilitiesGetOperationAST = require('graphql/utilities/getOperationAST'); | ||
var _parseBody = require('./parseBody'); | ||
@@ -90,4 +96,45 @@ | ||
// Run GraphQL query. | ||
var result = yield (0, _graphql.graphql)(schema, query, rootValue, variables, operationName); | ||
try { | ||
var result = yield new _bluebird2['default'](function (resolve) { | ||
var source = new _graphqlLanguage.Source(query, 'GraphQL request'); | ||
var documentAST = (0, _graphqlLanguage.parse)(source); | ||
var validationErrors = (0, _graphqlValidation.validate)(schema, documentAST); | ||
if (validationErrors.length > 0) { | ||
resolve({ errors: validationErrors }); | ||
} else { | ||
// Only query operations are allowed on GET requests. | ||
if (request.method === 'GET') { | ||
// Determine if this GET request will perform a non-query. | ||
var operationAST = (0, _graphqlUtilitiesGetOperationAST.getOperationAST)(documentAST, operationName); | ||
if (operationAST && operationAST.operation !== 'query') { | ||
// If GraphiQL can be shown, do not perform this query, but | ||
// provide it to GraphiQL so that the requester may perform it | ||
// themselves if desired. | ||
if (graphiql && canDisplayGraphiQL(request, data)) { | ||
response.type = 'text/html'; | ||
response.body = (0, _renderGraphiQL.renderGraphiQL)({ query: query, variables: variables }); | ||
resolve({ pass: true }); | ||
return; | ||
} | ||
// Otherwise, report a 405 Method Not Allowed error. | ||
response.set('Allow', 'POST'); | ||
sendError(response, (0, _httpErrors2['default'])(405, 'Can only perform a ' + operationAST.operation + ' operation ' + 'from a POST request.'), pretty); | ||
resolve({ pass: true }); | ||
} | ||
} | ||
// Perform the execution. | ||
resolve((0, _graphqlExecution.execute)(schema, documentAST, rootValue, variables, operationName)); | ||
} | ||
}); | ||
} catch (error) { | ||
result = { errors: [error] }; | ||
} | ||
if (result.pass) { | ||
return; | ||
} | ||
// Format any encountered errors. | ||
@@ -111,5 +158,5 @@ if (result.errors) { | ||
} | ||
} catch (error) { | ||
} catch (parseError) { | ||
// Format any request errors the same as GraphQL errors. | ||
return sendError(response, error, pretty); | ||
return sendError(response, parseError, pretty); | ||
} | ||
@@ -116,0 +163,0 @@ }; |
@@ -25,3 +25,3 @@ 'use strict'; | ||
/* eslint-disable max-len */ | ||
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.\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 <link href="//cdn.jsdelivr.net/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/0.13.3/react.min.js"></script>\n <script src="//cdn.jsdelivr.net/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 // Produce a Location query string from a parameter object.\n function locationQuery(params) {\n return \'?\' + Object.keys(params).map(function (key) {\n return encodeURIComponent(key) + \'=\' +\n encodeURIComponent(params[key]);\n }).join(\'&\');\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 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 // Defines a GraphQL fetcher using the fetch API.\n function graphQLFetcher(graphQLParams) {\n return fetch(fetchURL, {\n method: \'post\',\n headers: { \'Content-Type\': \'application/json\' },\n body: JSON.stringify(graphQLParams),\n }).then(function (response) {\n return response.json()\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 function onEditVariables(newVariables) {\n parameters.variables = newVariables;\n updateURL();\n }\n function updateURL() {\n history.replaceState(null, null, locationQuery(parameters));\n }\n // Render <GraphiQL /> into the body.\n React.render(\n React.createElement(GraphiQL, {\n fetcher: graphQLFetcher,\n onEditQuery: onEditQuery,\n onEditVariables: onEditVariables,\n query: ' + JSON.stringify(queryString) + ',\n response: ' + JSON.stringify(resultString) + ',\n variables: ' + JSON.stringify(variablesString) + '\n }),\n document.body\n );\n </script>\n</body>\n</html>'; | ||
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.\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 <link href="//cdn.jsdelivr.net/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/0.13.3/react.min.js"></script>\n <script src="//cdn.jsdelivr.net/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 // Produce a Location query string from a parameter object.\n function locationQuery(params) {\n return \'?\' + Object.keys(params).map(function (key) {\n return encodeURIComponent(key) + \'=\' +\n encodeURIComponent(params[key]);\n }).join(\'&\');\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 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 // Defines a GraphQL fetcher using the fetch API.\n function graphQLFetcher(graphQLParams) {\n return fetch(fetchURL, {\n method: \'post\',\n headers: { \'Content-Type\': \'application/json\' },\n body: JSON.stringify(graphQLParams),\n credentials: \'include\',\n }).then(function (response) {\n return response.json()\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 function onEditVariables(newVariables) {\n parameters.variables = newVariables;\n updateURL();\n }\n function updateURL() {\n history.replaceState(null, null, locationQuery(parameters));\n }\n // Render <GraphiQL /> into the body.\n React.render(\n React.createElement(GraphiQL, {\n fetcher: graphQLFetcher,\n onEditQuery: onEditQuery,\n onEditVariables: onEditVariables,\n query: ' + JSON.stringify(queryString) + ',\n response: ' + JSON.stringify(resultString) + ',\n variables: ' + JSON.stringify(variablesString) + '\n }),\n document.body\n );\n </script>\n</body>\n</html>'; | ||
} |
{ | ||
"name": "koa-graphql", | ||
"version": "0.4.0", | ||
"version": "0.4.1", | ||
"description": "Create a GraphQL HTTP server with Koa.", | ||
@@ -73,2 +73,3 @@ "contributors": [ | ||
"koa-mount": "^1.3.0", | ||
"koa-session": "^3.3.1", | ||
"mocha": "^2.2.5", | ||
@@ -75,0 +76,0 @@ "multer": "^1.0.3", |
@@ -62,5 +62,5 @@ # GraphQL Koa Middleware | ||
* **`raw`**: If the `graphiql` option is enabled and the `raw` parameter is | ||
provided raw JSON will always be returned instead of GraphiQL even when | ||
loaded from a browser. | ||
* **`raw`**: If the `graphiql` option is enabled and the `raw` parameter is | ||
provided raw JSON will always be returned instead of GraphiQL even when | ||
loaded from a browser. | ||
@@ -78,3 +78,3 @@ GraphQL will first look for each parameter in the URL's query-string: | ||
for `multipart/form-data` content, which may be useful for GraphQL mutations | ||
involving uploading files. See an [example using multer](https://github.com/chentsulin/koa-graphql/blob/master/src/__tests__/http-test.js#L458). | ||
involving uploading files. See an [example using multer](https://github.com/chentsulin/koa-graphql/blob/master/src/__tests__/http-test.js#L599). | ||
@@ -93,2 +93,47 @@ If the POST body has not yet been parsed, graphql-express will interpret it | ||
### Advanced Options | ||
In order to support advanced scenarios such as installing a GraphQL server on a | ||
dynamic endpoint or accessing the current authentication information, | ||
koa-graphql allows options to be provided as a function of each | ||
koa request. | ||
This example uses [`koa-session`][] to run GraphQL on a rootValue based on | ||
the currently logged-in session. | ||
```js | ||
var session = require('koa-session'); | ||
var graphqlHTTP = require('koa-graphql'); | ||
var app = koa(); | ||
app.keys = [ 'some secret hurr' ]; | ||
app.use(session(app)); | ||
app.use(function *(next) { | ||
this.session.id = 'me'; | ||
yield next; | ||
}); | ||
app.use(mount('/graphql', graphqlHTTP((request, context) => ({ | ||
schema: MySessionAwareGraphQLSchema, | ||
rootValue: { session: context.session }, | ||
graphiql: true | ||
})))); | ||
``` | ||
Then in your type definitions, access `session` from the rootValue: | ||
```js | ||
new GraphQLObjectType({ | ||
name: 'MyType', | ||
fields: { | ||
myField: { | ||
type: GraphQLString, | ||
resolve(parentValue, _, { rootValue: { session } }) { | ||
// use `session` here | ||
} | ||
} | ||
} | ||
}); | ||
``` | ||
### Contributing | ||
@@ -105,2 +150,3 @@ | ||
[`multer`]: https://github.com/expressjs/multer | ||
[`koa-session`]: https://github.com/koajs/session | ||
[npm-image]: https://img.shields.io/npm/v/koa-graphql.svg?style=flat-square | ||
@@ -107,0 +153,0 @@ [npm-url]: https://npmjs.org/package/koa-graphql |
26756
333
156
21