graphql-http 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/handler.js CHANGED
@@ -11,7 +11,7 @@ const utils_1 = require("./utils");
11
11
  /**
12
12
  * Checks whether the passed value is the `graphql-http` server agnostic response.
13
13
  *
14
- * @category Common
14
+ * @category Server
15
15
  */
16
16
  function isResponse(val) {
17
17
  // TODO: make sure the contents of init match ResponseInit
@@ -92,7 +92,7 @@ function createHandler(options) {
92
92
  },
93
93
  ];
94
94
  }
95
- const acceptedMediaType = getAcceptableMediaType(req.headers.accept);
95
+ const acceptedMediaType = getAcceptableMediaType(getHeader(req, 'accept'));
96
96
  if (!acceptedMediaType) {
97
97
  return [
98
98
  null,
@@ -107,7 +107,7 @@ function createHandler(options) {
107
107
  }
108
108
  // TODO: should graphql-http care about content-encoding? I'd say unzipping should happen before handler is reached
109
109
  const [mediaType, charset = 'charset=utf-8', // utf-8 is assumed when not specified. this parameter is either "charset" or "boundary" (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length)
110
- ] = (req.headers['content-type'] || '')
110
+ ] = (getHeader(req, 'content-type') || '')
111
111
  .replace(/\s/g, '')
112
112
  .toLowerCase()
113
113
  .split(';');
@@ -208,10 +208,14 @@ function createHandler(options) {
208
208
  catch (err) {
209
209
  return makeResponse(err, acceptedMediaType);
210
210
  }
211
+ const resOrContext = typeof context === 'function' ? await context(req, params) : context;
212
+ if (isResponse(resOrContext))
213
+ return resOrContext;
211
214
  const argsWithoutSchema = {
212
215
  operationName,
213
216
  document,
214
217
  variableValues: variables,
218
+ contextValue: resOrContext,
215
219
  };
216
220
  if (typeof schema === 'function') {
217
221
  const resOrSchema = await schema(req, argsWithoutSchema);
@@ -257,10 +261,10 @@ function createHandler(options) {
257
261
  ];
258
262
  }
259
263
  if (!('contextValue' in args)) {
260
- const maybeResOrContext = typeof context === 'function' ? await context(req, args) : context;
261
- if (isResponse(maybeResOrContext))
262
- return maybeResOrContext;
263
- args.contextValue = maybeResOrContext;
264
+ const resOrContext = typeof context === 'function' ? await context(req, params) : context;
265
+ if (isResponse(resOrContext))
266
+ return resOrContext;
267
+ args.contextValue = resOrContext;
264
268
  }
265
269
  let result = await execute(args);
266
270
  const maybeResponseOrResult = await (onOperation === null || onOperation === void 0 ? void 0 : onOperation(req, args, result));
@@ -356,3 +360,9 @@ function makeResponse(resultOrErrors, acceptedMediaType) {
356
360
  ];
357
361
  }
358
362
  exports.makeResponse = makeResponse;
363
+ function getHeader(req, key) {
364
+ if (typeof req.headers.get === 'function') {
365
+ return req.headers.get(key);
366
+ }
367
+ return Object(req.headers)[key];
368
+ }
package/lib/handler.mjs CHANGED
@@ -8,7 +8,7 @@ import { areGraphQLErrors, isAsyncIterable, isExecutionResult, isObject, } from
8
8
  /**
9
9
  * Checks whether the passed value is the `graphql-http` server agnostic response.
10
10
  *
11
- * @category Common
11
+ * @category Server
12
12
  */
13
13
  export function isResponse(val) {
14
14
  // TODO: make sure the contents of init match ResponseInit
@@ -35,7 +35,7 @@ export function isResponse(val) {
35
35
  * ```js
36
36
  * import http from 'http';
37
37
  * import { createHandler } from 'graphql-http';
38
- * import { schema } from './my-graphql-schema.mjs';
38
+ * import { schema } from './my-graphql-schema/index.mjs';
39
39
  *
40
40
  * // Create the GraphQL over HTTP handler
41
41
  * const handler = createHandler({ schema });
@@ -88,7 +88,7 @@ export function createHandler(options) {
88
88
  },
89
89
  ];
90
90
  }
91
- const acceptedMediaType = getAcceptableMediaType(req.headers.accept);
91
+ const acceptedMediaType = getAcceptableMediaType(getHeader(req, 'accept'));
92
92
  if (!acceptedMediaType) {
93
93
  return [
94
94
  null,
@@ -103,7 +103,7 @@ export function createHandler(options) {
103
103
  }
104
104
  // TODO: should graphql-http care about content-encoding? I'd say unzipping should happen before handler is reached
105
105
  const [mediaType, charset = 'charset=utf-8', // utf-8 is assumed when not specified. this parameter is either "charset" or "boundary" (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length)
106
- ] = (req.headers['content-type'] || '')
106
+ ] = (getHeader(req, 'content-type') || '')
107
107
  .replace(/\s/g, '')
108
108
  .toLowerCase()
109
109
  .split(';');
@@ -204,10 +204,14 @@ export function createHandler(options) {
204
204
  catch (err) {
205
205
  return makeResponse(err, acceptedMediaType);
206
206
  }
207
+ const resOrContext = typeof context === 'function' ? await context(req, params) : context;
208
+ if (isResponse(resOrContext))
209
+ return resOrContext;
207
210
  const argsWithoutSchema = {
208
211
  operationName,
209
212
  document,
210
213
  variableValues: variables,
214
+ contextValue: resOrContext,
211
215
  };
212
216
  if (typeof schema === 'function') {
213
217
  const resOrSchema = await schema(req, argsWithoutSchema);
@@ -253,10 +257,10 @@ export function createHandler(options) {
253
257
  ];
254
258
  }
255
259
  if (!('contextValue' in args)) {
256
- const maybeResOrContext = typeof context === 'function' ? await context(req, args) : context;
257
- if (isResponse(maybeResOrContext))
258
- return maybeResOrContext;
259
- args.contextValue = maybeResOrContext;
260
+ const resOrContext = typeof context === 'function' ? await context(req, params) : context;
261
+ if (isResponse(resOrContext))
262
+ return resOrContext;
263
+ args.contextValue = resOrContext;
260
264
  }
261
265
  let result = await execute(args);
262
266
  const maybeResponseOrResult = await (onOperation === null || onOperation === void 0 ? void 0 : onOperation(req, args, result));
@@ -349,3 +353,9 @@ export function makeResponse(resultOrErrors, acceptedMediaType) {
349
353
  } }),
350
354
  ];
351
355
  }
356
+ function getHeader(req, key) {
357
+ if (typeof req.headers.get === 'function') {
358
+ return req.headers.get(key);
359
+ }
360
+ return Object(req.headers)[key];
361
+ }
@@ -0,0 +1,4 @@
1
+ export * from './common';
2
+ export * from './handler';
3
+ export * from './client';
4
+ export * from './audits';
package/lib/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  export * from './common.mjs';
2
2
  export * from './handler.mjs';
3
3
  export * from './client.mjs';
4
- export * from './audits.mjs';
4
+ export * from './audits/index.mjs';
@@ -0,0 +1,21 @@
1
+ import type { Request, Handler } from 'express';
2
+ import { HandlerOptions, OperationContext } from '../handler';
3
+ /**
4
+ * Create a GraphQL over HTTP Protocol compliant request handler for
5
+ * the express framework.
6
+ *
7
+ * ```js
8
+ * import express from 'express'; // yarn add express
9
+ * import { createHandler } from 'graphql-http/lib/use/express';
10
+ * import { schema } from './my-graphql-schema';
11
+ *
12
+ * const app = express();
13
+ * app.all('/graphql', createHandler({ schema }));
14
+ *
15
+ * app.listen({ port: 4000 });
16
+ * console.log('Listening to port 4000');
17
+ * ```
18
+ *
19
+ * @category Server/express
20
+ */
21
+ export declare function createHandler<Context extends OperationContext = undefined>(options: HandlerOptions<Request, undefined, Context>): Handler;
@@ -0,0 +1,21 @@
1
+ import type { Request, Handler } from 'express';
2
+ import { HandlerOptions, OperationContext } from '../handler';
3
+ /**
4
+ * Create a GraphQL over HTTP Protocol compliant request handler for
5
+ * the express framework.
6
+ *
7
+ * ```js
8
+ * import express from 'express'; // yarn add express
9
+ * import { createHandler } from 'graphql-http/lib/use/express';
10
+ * import { schema } from './my-graphql-schema';
11
+ *
12
+ * const app = express();
13
+ * app.all('/graphql', createHandler({ schema }));
14
+ *
15
+ * app.listen({ port: 4000 });
16
+ * console.log('Listening to port 4000');
17
+ * ```
18
+ *
19
+ * @category Server/express
20
+ */
21
+ export declare function createHandler<Context extends OperationContext = undefined>(options: HandlerOptions<Request, undefined, Context>): Handler;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createHandler = void 0;
4
+ const handler_1 = require("../handler");
5
+ /**
6
+ * Create a GraphQL over HTTP Protocol compliant request handler for
7
+ * the express framework.
8
+ *
9
+ * ```js
10
+ * import express from 'express'; // yarn add express
11
+ * import { createHandler } from 'graphql-http/lib/use/express';
12
+ * import { schema } from './my-graphql-schema';
13
+ *
14
+ * const app = express();
15
+ * app.all('/graphql', createHandler({ schema }));
16
+ *
17
+ * app.listen({ port: 4000 });
18
+ * console.log('Listening to port 4000');
19
+ * ```
20
+ *
21
+ * @category Server/express
22
+ */
23
+ function createHandler(options) {
24
+ const isProd = process.env.NODE_ENV === 'production';
25
+ const handle = (0, handler_1.createHandler)(options);
26
+ return async function requestListener(req, res) {
27
+ try {
28
+ const [body, init] = await handle({
29
+ url: req.url,
30
+ method: req.method,
31
+ headers: req.headers,
32
+ body: () => {
33
+ if (req.body) {
34
+ // in case express has a body parser
35
+ return req.body;
36
+ }
37
+ return new Promise((resolve) => {
38
+ let body = '';
39
+ req.on('data', (chunk) => (body += chunk));
40
+ req.on('end', () => resolve(body));
41
+ });
42
+ },
43
+ raw: req,
44
+ context: undefined,
45
+ });
46
+ res.writeHead(init.status, init.statusText, init.headers).end(body);
47
+ }
48
+ catch (err) {
49
+ // The handler shouldnt throw errors.
50
+ // If you wish to handle them differently, consider implementing your own request handler.
51
+ console.error('Internal error occurred during request handling. ' +
52
+ 'Please check your implementation.', err);
53
+ if (isProd) {
54
+ res.writeHead(500).end();
55
+ }
56
+ else {
57
+ res
58
+ .writeHead(500, { 'content-type': 'application/json; charset=utf-8' })
59
+ .end(JSON.stringify({
60
+ errors: [
61
+ err instanceof Error
62
+ ? {
63
+ message: err.message,
64
+ stack: err.stack,
65
+ }
66
+ : err,
67
+ ],
68
+ }));
69
+ }
70
+ }
71
+ };
72
+ }
73
+ exports.createHandler = createHandler;
@@ -0,0 +1,69 @@
1
+ import { createHandler as createRawHandler, } from '../handler.mjs';
2
+ /**
3
+ * Create a GraphQL over HTTP Protocol compliant request handler for
4
+ * the express framework.
5
+ *
6
+ * ```js
7
+ * import express from 'express'; // yarn add express
8
+ * import { createHandler } from 'graphql-http/lib/use/express';
9
+ * import { schema } from './my-graphql-schema/index.mjs';
10
+ *
11
+ * const app = express();
12
+ * app.all('/graphql', createHandler({ schema }));
13
+ *
14
+ * app.listen({ port: 4000 });
15
+ * console.log('Listening to port 4000');
16
+ * ```
17
+ *
18
+ * @category Server/express
19
+ */
20
+ export function createHandler(options) {
21
+ const isProd = process.env.NODE_ENV === 'production';
22
+ const handle = createRawHandler(options);
23
+ return async function requestListener(req, res) {
24
+ try {
25
+ const [body, init] = await handle({
26
+ url: req.url,
27
+ method: req.method,
28
+ headers: req.headers,
29
+ body: () => {
30
+ if (req.body) {
31
+ // in case express has a body parser
32
+ return req.body;
33
+ }
34
+ return new Promise((resolve) => {
35
+ let body = '';
36
+ req.on('data', (chunk) => (body += chunk));
37
+ req.on('end', () => resolve(body));
38
+ });
39
+ },
40
+ raw: req,
41
+ context: undefined,
42
+ });
43
+ res.writeHead(init.status, init.statusText, init.headers).end(body);
44
+ }
45
+ catch (err) {
46
+ // The handler shouldnt throw errors.
47
+ // If you wish to handle them differently, consider implementing your own request handler.
48
+ console.error('Internal error occurred during request handling. ' +
49
+ 'Please check your implementation.', err);
50
+ if (isProd) {
51
+ res.writeHead(500).end();
52
+ }
53
+ else {
54
+ res
55
+ .writeHead(500, { 'content-type': 'application/json; charset=utf-8' })
56
+ .end(JSON.stringify({
57
+ errors: [
58
+ err instanceof Error
59
+ ? {
60
+ message: err.message,
61
+ stack: err.stack,
62
+ }
63
+ : err,
64
+ ],
65
+ }));
66
+ }
67
+ }
68
+ };
69
+ }
@@ -0,0 +1,21 @@
1
+ import type { FastifyRequest, RouteHandler } from 'fastify';
2
+ import { HandlerOptions, OperationContext } from '../handler';
3
+ /**
4
+ * Create a GraphQL over HTTP Protocol compliant request handler for
5
+ * the fastify framework.
6
+ *
7
+ * ```js
8
+ * import Fastify from 'fastify'; // yarn add fastify
9
+ * import { createHandler } from 'graphql-http/lib/use/express';
10
+ * import { schema } from './my-graphql-schema';
11
+ *
12
+ * const fastify = Fastify();
13
+ * fastify.all('/graphql', createHandler({ schema }));
14
+ *
15
+ * fastify.listen({ port: 4000 });
16
+ * console.log('Listening to port 4000');
17
+ * ```
18
+ *
19
+ * @category Server/fastify
20
+ */
21
+ export declare function createHandler<Context extends OperationContext = undefined>(options: HandlerOptions<FastifyRequest, undefined, Context>): RouteHandler;
@@ -0,0 +1,21 @@
1
+ import type { FastifyRequest, RouteHandler } from 'fastify';
2
+ import { HandlerOptions, OperationContext } from '../handler';
3
+ /**
4
+ * Create a GraphQL over HTTP Protocol compliant request handler for
5
+ * the fastify framework.
6
+ *
7
+ * ```js
8
+ * import Fastify from 'fastify'; // yarn add fastify
9
+ * import { createHandler } from 'graphql-http/lib/use/express';
10
+ * import { schema } from './my-graphql-schema';
11
+ *
12
+ * const fastify = Fastify();
13
+ * fastify.all('/graphql', createHandler({ schema }));
14
+ *
15
+ * fastify.listen({ port: 4000 });
16
+ * console.log('Listening to port 4000');
17
+ * ```
18
+ *
19
+ * @category Server/fastify
20
+ */
21
+ export declare function createHandler<Context extends OperationContext = undefined>(options: HandlerOptions<FastifyRequest, undefined, Context>): RouteHandler;
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createHandler = void 0;
4
+ const handler_1 = require("../handler");
5
+ /**
6
+ * Create a GraphQL over HTTP Protocol compliant request handler for
7
+ * the fastify framework.
8
+ *
9
+ * ```js
10
+ * import Fastify from 'fastify'; // yarn add fastify
11
+ * import { createHandler } from 'graphql-http/lib/use/express';
12
+ * import { schema } from './my-graphql-schema';
13
+ *
14
+ * const fastify = Fastify();
15
+ * fastify.all('/graphql', createHandler({ schema }));
16
+ *
17
+ * fastify.listen({ port: 4000 });
18
+ * console.log('Listening to port 4000');
19
+ * ```
20
+ *
21
+ * @category Server/fastify
22
+ */
23
+ function createHandler(options) {
24
+ const isProd = process.env.NODE_ENV === 'production';
25
+ const handle = (0, handler_1.createHandler)(options);
26
+ return async function requestListener(req, reply) {
27
+ try {
28
+ const [body, init] = await handle({
29
+ url: req.url,
30
+ method: req.method,
31
+ headers: req.headers,
32
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
+ body: req.body,
34
+ raw: req,
35
+ context: undefined,
36
+ });
37
+ reply
38
+ .status(init.status)
39
+ .headers(init.headers || {})
40
+ // "or undefined" because `null` will be JSON stringified
41
+ .send(body || undefined);
42
+ }
43
+ catch (err) {
44
+ // The handler shouldnt throw errors.
45
+ // If you wish to handle them differently, consider implementing your own request handler.
46
+ console.error('Internal error occurred during request handling. ' +
47
+ 'Please check your implementation.', err);
48
+ if (isProd) {
49
+ reply.status(500).send();
50
+ }
51
+ else {
52
+ reply
53
+ .status(500)
54
+ .header('content-type', 'application/json; charset=utf-8')
55
+ .send({
56
+ errors: [
57
+ err instanceof Error
58
+ ? {
59
+ message: err.message,
60
+ stack: err.stack,
61
+ }
62
+ : err,
63
+ ],
64
+ });
65
+ }
66
+ }
67
+ };
68
+ }
69
+ exports.createHandler = createHandler;
@@ -0,0 +1,65 @@
1
+ import { createHandler as createRawHandler, } from '../handler.mjs';
2
+ /**
3
+ * Create a GraphQL over HTTP Protocol compliant request handler for
4
+ * the fastify framework.
5
+ *
6
+ * ```js
7
+ * import Fastify from 'fastify'; // yarn add fastify
8
+ * import { createHandler } from 'graphql-http/lib/use/express';
9
+ * import { schema } from './my-graphql-schema/index.mjs';
10
+ *
11
+ * const fastify = Fastify();
12
+ * fastify.all('/graphql', createHandler({ schema }));
13
+ *
14
+ * fastify.listen({ port: 4000 });
15
+ * console.log('Listening to port 4000');
16
+ * ```
17
+ *
18
+ * @category Server/fastify
19
+ */
20
+ export function createHandler(options) {
21
+ const isProd = process.env.NODE_ENV === 'production';
22
+ const handle = createRawHandler(options);
23
+ return async function requestListener(req, reply) {
24
+ try {
25
+ const [body, init] = await handle({
26
+ url: req.url,
27
+ method: req.method,
28
+ headers: req.headers,
29
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
30
+ body: req.body,
31
+ raw: req,
32
+ context: undefined,
33
+ });
34
+ reply
35
+ .status(init.status)
36
+ .headers(init.headers || {})
37
+ // "or undefined" because `null` will be JSON stringified
38
+ .send(body || undefined);
39
+ }
40
+ catch (err) {
41
+ // The handler shouldnt throw errors.
42
+ // If you wish to handle them differently, consider implementing your own request handler.
43
+ console.error('Internal error occurred during request handling. ' +
44
+ 'Please check your implementation.', err);
45
+ if (isProd) {
46
+ reply.status(500).send();
47
+ }
48
+ else {
49
+ reply
50
+ .status(500)
51
+ .header('content-type', 'application/json; charset=utf-8')
52
+ .send({
53
+ errors: [
54
+ err instanceof Error
55
+ ? {
56
+ message: err.message,
57
+ stack: err.stack,
58
+ }
59
+ : err,
60
+ ],
61
+ });
62
+ }
63
+ }
64
+ };
65
+ }
@@ -0,0 +1,40 @@
1
+ import { HandlerOptions, OperationContext } from '../handler';
2
+ /**
3
+ * The necessary API from the fetch environment for the handler.
4
+ *
5
+ * @category Server/fetch
6
+ */
7
+ export interface FetchAPI {
8
+ Response: typeof Response;
9
+ ReadableStream: typeof ReadableStream;
10
+ TextEncoder: typeof TextEncoder;
11
+ }
12
+ /**
13
+ * Create a GraphQL over HTTP Protocol compliant request handler for
14
+ * a fetch environment like Deno, Bun, CloudFlare Workers, Lambdas, etc.
15
+ *
16
+ * You can use [@whatwg-node/server](https://github.com/ardatan/whatwg-node/tree/master/packages/server) to create a server adapter and
17
+ * isomorphically use it in _any_ environment. See an example:
18
+ *
19
+ * ```js
20
+ * import http from 'http';
21
+ * import { createServerAdapter } from '@whatwg-node/server'; // yarn add @whatwg-node/server
22
+ * import { createHandler } from 'graphql-http/lib/use/fetch';
23
+ * import { schema } from './my-graphql-step';
24
+ *
25
+ * // Use this adapter in _any_ environment.
26
+ * const adapter = createServerAdapter({
27
+ * handleRequest: createHandler({ schema }),
28
+ * });
29
+ *
30
+ * const server = http.createServer(adapter);
31
+ *
32
+ * server.listen(4000);
33
+ * console.log('Listening to port 4000');
34
+ * ```
35
+ *
36
+ * @param fetchApi - Custom fetch API engine, will use from global scope if left undefined.
37
+ *
38
+ * @category Server/fetch
39
+ */
40
+ export declare function createHandler<Context extends OperationContext = undefined>(options: HandlerOptions<Request, FetchAPI, Context>, fetchApi?: Partial<FetchAPI>): (req: Request) => Promise<Response>;
@@ -0,0 +1,40 @@
1
+ import { HandlerOptions, OperationContext } from '../handler';
2
+ /**
3
+ * The necessary API from the fetch environment for the handler.
4
+ *
5
+ * @category Server/fetch
6
+ */
7
+ export interface FetchAPI {
8
+ Response: typeof Response;
9
+ ReadableStream: typeof ReadableStream;
10
+ TextEncoder: typeof TextEncoder;
11
+ }
12
+ /**
13
+ * Create a GraphQL over HTTP Protocol compliant request handler for
14
+ * a fetch environment like Deno, Bun, CloudFlare Workers, Lambdas, etc.
15
+ *
16
+ * You can use [@whatwg-node/server](https://github.com/ardatan/whatwg-node/tree/master/packages/server) to create a server adapter and
17
+ * isomorphically use it in _any_ environment. See an example:
18
+ *
19
+ * ```js
20
+ * import http from 'http';
21
+ * import { createServerAdapter } from '@whatwg-node/server'; // yarn add @whatwg-node/server
22
+ * import { createHandler } from 'graphql-http/lib/use/fetch';
23
+ * import { schema } from './my-graphql-step';
24
+ *
25
+ * // Use this adapter in _any_ environment.
26
+ * const adapter = createServerAdapter({
27
+ * handleRequest: createHandler({ schema }),
28
+ * });
29
+ *
30
+ * const server = http.createServer(adapter);
31
+ *
32
+ * server.listen(4000);
33
+ * console.log('Listening to port 4000');
34
+ * ```
35
+ *
36
+ * @param fetchApi - Custom fetch API engine, will use from global scope if left undefined.
37
+ *
38
+ * @category Server/fetch
39
+ */
40
+ export declare function createHandler<Context extends OperationContext = undefined>(options: HandlerOptions<Request, FetchAPI, Context>, fetchApi?: Partial<FetchAPI>): (req: Request) => Promise<Response>;