UNPKG

12.2 kBMarkdownView Raw
1# GraphQL HTTP Server Middleware
2
3[![npm version](https://badge.fury.io/js/express-graphql.svg)](https://badge.fury.io/js/express-graphql)
4[![Build Status](https://github.com/graphql/express-graphql/workflows/CI/badge.svg?branch=master)](https://github.com/graphql/express-graphql/actions?query=branch%3Amaster)
5[![Coverage Status](https://codecov.io/gh/graphql/express-graphql/branch/master/graph/badge.svg)](https://codecov.io/gh/graphql/express-graphql)
6
7Create a GraphQL HTTP server with any HTTP web framework that supports connect styled middleware, including [Connect](https://github.com/senchalabs/connect) itself, [Express](https://expressjs.com) and [Restify](http://restify.com/).
8
9## Installation
10
11```sh
12npm install --save express-graphql
13```
14
15### TypeScript
16
17This module includes a [TypeScript](https://www.typescriptlang.org/)
18declaration file to enable auto complete in compatible editors and type
19information for TypeScript projects.
20
21## Simple Setup
22
23Just mount `express-graphql` as a route handler:
24
25```js
26const express = require('express');
27const { graphqlHTTP } = require('express-graphql');
28
29const app = express();
30
31app.use(
32 '/graphql',
33 graphqlHTTP({
34 schema: MyGraphQLSchema,
35 graphiql: true,
36 }),
37);
38
39app.listen(4000);
40```
41
42## Setup with Restify
43
44Use `.get` or `.post` (or both) rather than `.use` to configure your route handler. If you want to show GraphiQL in the browser, set `graphiql: true` on your `.get` handler.
45
46```js
47const restify = require('restify');
48const { graphqlHTTP } = require('express-graphql');
49
50const app = restify.createServer();
51
52app.post(
53 '/graphql',
54 graphqlHTTP({
55 schema: MyGraphQLSchema,
56 graphiql: false,
57 }),
58);
59
60app.get(
61 '/graphql',
62 graphqlHTTP({
63 schema: MyGraphQLSchema,
64 graphiql: true,
65 }),
66);
67
68app.listen(4000);
69```
70
71## Options
72
73The `graphqlHTTP` function accepts the following options:
74
75- **`schema`**: A `GraphQLSchema` instance from [`GraphQL.js`][].
76 A `schema` _must_ be provided.
77
78- **`graphiql`**: If `true`, presents [GraphiQL][] when the GraphQL endpoint is
79 loaded in a browser. We recommend that you set `graphiql` to `true` when your
80 app is in development, because it's quite useful. You may or may not want it
81 in production.
82 Alternatively, instead of `true` you can pass in an options object:
83
84 - **`defaultQuery`**: An optional GraphQL string to use when no query
85 is provided and no stored query exists from a previous session.
86 If undefined is provided, GraphiQL will use its own default query.
87
88 - **`headerEditorEnabled`**: An optional boolean which enables the header editor when true.
89 Defaults to false.
90
91- **`rootValue`**: A value to pass as the `rootValue` to the `graphql()`
92 function from [`GraphQL.js/src/execute.js`](https://github.com/graphql/graphql-js/blob/master/src/execution/execute.js#L119).
93
94- **`context`**: A value to pass as the `context` to the `graphql()`
95 function from [`GraphQL.js/src/execute.js`](https://github.com/graphql/graphql-js/blob/master/src/execution/execute.js#L120). If `context` is not provided, the
96 `request` object is passed as the context.
97
98- **`pretty`**: If `true`, any JSON response will be pretty-printed.
99
100- **`extensions`**: An optional function for adding additional metadata to the
101 GraphQL response as a key-value object. The result will be added to the
102 `"extensions"` field in the resulting JSON. This is often a useful place to
103 add development time metadata such as the runtime of a query or the amount
104 of resources consumed. This may be an async function. The function is
105 given one object as an argument: `{ document, variables, operationName, result, context }`.
106
107- **`validationRules`**: Optional additional validation rules queries must
108 satisfy in addition to those defined by the GraphQL spec.
109
110- **`customValidateFn`**: An optional function which will be used to validate
111 instead of default `validate` from `graphql-js`.
112
113- **`customExecuteFn`**: An optional function which will be used to execute
114 instead of default `execute` from `graphql-js`.
115
116- **`customFormatErrorFn`**: An optional function which will be used to format any
117 errors produced by fulfilling a GraphQL operation. If no function is
118 provided, GraphQL's default spec-compliant [`formatError`][] function will be used.
119
120- **`customParseFn`**: An optional function which will be used to create a document
121 instead of the default `parse` from `graphql-js`.
122
123- **`formatError`**: is deprecated and replaced by `customFormatErrorFn`. It will be
124 removed in version 1.0.0.
125
126In addition to an object defining each option, options can also be provided as
127a function (or async function) which returns this options object. This function
128is provided the arguments `(request, response, graphQLParams)` and is called
129after the request has been parsed.
130
131The `graphQLParams` is provided as the object `{ query, variables, operationName, raw }`.
132
133```js
134app.use(
135 '/graphql',
136 graphqlHTTP(async (request, response, graphQLParams) => ({
137 schema: MyGraphQLSchema,
138 rootValue: await someFunctionToGetRootValue(request),
139 graphiql: true,
140 })),
141);
142```
143
144## HTTP Usage
145
146Once installed at a path, `express-graphql` will accept requests with
147the parameters:
148
149- **`query`**: A string GraphQL document to be executed.
150
151- **`variables`**: The runtime values to use for any GraphQL query variables
152 as a JSON object.
153
154- **`operationName`**: If the provided `query` contains multiple named
155 operations, this specifies which operation should be executed. If not
156 provided, a 400 error will be returned if the `query` contains multiple
157 named operations.
158
159- **`raw`**: If the `graphiql` option is enabled and the `raw` parameter is
160 provided raw JSON will always be returned instead of GraphiQL even when
161 loaded from a browser.
162
163GraphQL will first look for each parameter in the query string of a URL:
164
165```
166/graphql?query=query+getUser($id:ID){user(id:$id){name}}&variables={"id":"4"}
167```
168
169If not found in the query-string, it will look in the POST request body.
170
171If a previous middleware has already parsed the POST body, the `request.body`
172value will be used. Use [`multer`][] or a similar middleware to add support
173for `multipart/form-data` content, which may be useful for GraphQL mutations
174involving uploading files. See an [example using multer](https://github.com/graphql/express-graphql/blob/304b24b993c8f16fffff8d23b0fa4088e690874b/src/__tests__/http-test.js#L674-L741).
175
176If the POST body has not yet been parsed, express-graphql will interpret it
177depending on the provided _Content-Type_ header.
178
179- **`application/json`**: the POST body will be parsed as a JSON
180 object of parameters.
181
182- **`application/x-www-form-urlencoded`**: this POST body will be
183 parsed as a url-encoded string of key-value pairs.
184
185- **`application/graphql`**: The POST body will be parsed as GraphQL
186 query string, which provides the `query` parameter.
187
188## Combining with Other Express Middleware
189
190By default, the express request is passed as the GraphQL `context`.
191Since most express middleware operates by adding extra data to the
192request object, this means you can use most express middleware just by inserting it before `graphqlHTTP` is mounted. This covers scenarios such as authenticating the user, handling file uploads, or mounting GraphQL on a dynamic endpoint.
193
194This example uses [`express-session`][] to provide GraphQL with the currently logged-in session.
195
196```js
197const session = require('express-session');
198const { graphqlHTTP } = require('express-graphql');
199
200const app = express();
201
202app.use(session({ secret: 'keyboard cat', cookie: { maxAge: 60000 } }));
203
204app.use(
205 '/graphql',
206 graphqlHTTP({
207 schema: MySessionAwareGraphQLSchema,
208 graphiql: true,
209 }),
210);
211```
212
213Then in your type definitions, you can access the request via the third "context" argument in your `resolve` function:
214
215```js
216new GraphQLObjectType({
217 name: 'MyType',
218 fields: {
219 myField: {
220 type: GraphQLString,
221 resolve(parentValue, args, request) {
222 // use `request.session` here
223 },
224 },
225 },
226});
227```
228
229## Providing Extensions
230
231The GraphQL response allows for adding additional information in a response to
232a GraphQL query via a field in the response called `"extensions"`. This is added
233by providing an `extensions` function when using `graphqlHTTP`. The function
234must return a JSON-serializable Object.
235
236When called, this is provided an argument which you can use to get information
237about the GraphQL request:
238
239`{ document, variables, operationName, result, context }`
240
241This example illustrates adding the amount of time consumed by running the
242provided query, which could perhaps be used by your development tools.
243
244```js
245const { graphqlHTTP } = require('express-graphql');
246
247const app = express();
248
249app.use(session({ secret: 'keyboard cat', cookie: { maxAge: 60000 } }));
250
251const extensions = ({
252 document,
253 variables,
254 operationName,
255 result,
256 context,
257}) => {
258 return {
259 runTime: Date.now() - context.startTime,
260 };
261};
262
263app.use(
264 '/graphql',
265 graphqlHTTP((request) => {
266 return {
267 schema: MyGraphQLSchema,
268 context: { startTime: Date.now() },
269 graphiql: true,
270 extensions,
271 };
272 }),
273);
274```
275
276When querying this endpoint, it would include this information in the result,
277for example:
278
279```js
280{
281 "data": { ... }
282 "extensions": {
283 "runTime": 135
284 }
285}
286```
287
288## Additional Validation Rules
289
290GraphQL's [validation phase](https://graphql.github.io/graphql-spec/#sec-Validation) checks the query to ensure that it can be successfully executed against the schema. The `validationRules` option allows for additional rules to be run during this phase. Rules are applied to each node in an AST representing the query using the Visitor pattern.
291
292A validation rule is a function which returns a visitor for one or more node Types. Below is an example of a validation preventing the specific field name `metadata` from being queried. For more examples see the [`specifiedRules`](https://github.com/graphql/graphql-js/tree/master/src/validation/rules) in the [graphql-js](https://github.com/graphql/graphql-js) package.
293
294```js
295import { GraphQLError } from 'graphql';
296
297export function DisallowMetadataQueries(context) {
298 return {
299 Field(node) {
300 const fieldName = node.name.value;
301
302 if (fieldName === 'metadata') {
303 context.reportError(
304 new GraphQLError(
305 `Validation: Requesting the field ${fieldName} is not allowed`,
306 ),
307 );
308 }
309 },
310 };
311}
312```
313
314### Disabling introspection
315
316Disabling introspection does not reflect best practices and does not necessarily make your
317application any more secure. Nevertheless, disabling introspection is possible by utilizing the
318`NoSchemaIntrospectionCustomRule` provided by the [graphql-js](https://github.com/graphql/graphql-js)
319package.
320
321```js
322import { specifiedRules, NoSchemaIntrospectionCustomRule } from 'graphql';
323
324app.use(
325 '/graphql',
326 graphqlHTTP((request) => {
327 return {
328 schema: MyGraphQLSchema,
329 validationRules: [...specifiedRules, NoSchemaIntrospectionCustomRule],
330 };
331 }),
332);
333```
334
335## Other Exports
336
337**`getGraphQLParams(request: Request): Promise<GraphQLParams>`**
338
339Given an HTTP Request, this returns a Promise for the parameters relevant to
340running a GraphQL request. This function is used internally to handle the
341incoming request, you may use it directly for building other similar services.
342
343```js
344const { getGraphQLParams } = require('express-graphql');
345
346getGraphQLParams(request).then((params) => {
347 // do something...
348});
349```
350
351## Debugging Tips
352
353During development, it's useful to get more information from errors, such as
354stack traces. Providing a function to `customFormatErrorFn` enables this:
355
356```js
357customFormatErrorFn: (error) => ({
358 message: error.message,
359 locations: error.locations,
360 stack: error.stack ? error.stack.split('\n') : [],
361 path: error.path,
362});
363```
364
365[`graphql.js`]: https://github.com/graphql/graphql-js
366[`formaterror`]: https://github.com/graphql/graphql-js/blob/master/src/error/formatError.js
367[graphiql]: https://github.com/graphql/graphiql
368[`multer`]: https://github.com/expressjs/multer
369[`express-session`]: https://github.com/expressjs/session