graphql-http 1.6.1 → 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/LICENSE.md +1 -1
- package/README.md +123 -114
- package/lib/audits/server.js +15 -12
- package/lib/audits/server.mjs +15 -12
- package/lib/audits/utils.d.mts +1 -1
- package/lib/audits/utils.d.ts +1 -1
- package/lib/handler.d.mts +26 -24
- package/lib/handler.d.ts +26 -24
- package/lib/handler.js +17 -7
- package/lib/handler.mjs +17 -7
- package/lib/use/express.d.mts +21 -0
- package/lib/use/express.d.ts +21 -0
- package/lib/use/express.js +73 -0
- package/lib/use/express.mjs +69 -0
- package/lib/use/fastify.d.mts +21 -0
- package/lib/use/fastify.d.ts +21 -0
- package/lib/use/fastify.js +69 -0
- package/lib/use/fastify.mjs +65 -0
- package/lib/use/fetch.d.mts +40 -0
- package/lib/use/fetch.d.ts +40 -0
- package/lib/use/fetch.js +81 -0
- package/lib/use/fetch.mjs +77 -0
- package/lib/use/node.d.mts +21 -0
- package/lib/use/node.d.ts +21 -0
- package/lib/use/node.js +72 -0
- package/lib/use/node.mjs +68 -0
- package/package.json +44 -20
- package/umd/graphql-http.js +0 -2
- package/umd/graphql-http.min.js +1 -1
- package/umd/graphql-http.min.js.gz +0 -0
package/lib/handler.d.ts
CHANGED
|
@@ -8,27 +8,25 @@ import { RequestParams } from './common';
|
|
|
8
8
|
/**
|
|
9
9
|
* The incoming request headers the implementing server should provide.
|
|
10
10
|
*
|
|
11
|
-
* @category
|
|
11
|
+
* @category Server
|
|
12
12
|
*/
|
|
13
|
-
export
|
|
14
|
-
accept?: string | undefined;
|
|
15
|
-
allow?: string | undefined;
|
|
16
|
-
'content-type'?: string | undefined;
|
|
13
|
+
export declare type RequestHeaders = {
|
|
17
14
|
/**
|
|
18
15
|
* Always an array in Node. Duplicates are added to it.
|
|
19
|
-
* Not necessarily true for other environments
|
|
20
|
-
* to check the type during runtime.
|
|
16
|
+
* Not necessarily true for other environments.
|
|
21
17
|
*/
|
|
22
18
|
'set-cookie'?: string | string[] | undefined;
|
|
23
19
|
[key: string]: string | string[] | undefined;
|
|
24
|
-
}
|
|
20
|
+
} | {
|
|
21
|
+
get: (key: string) => string | null;
|
|
22
|
+
};
|
|
25
23
|
/**
|
|
26
24
|
* Server agnostic request interface containing the raw request
|
|
27
25
|
* which is server dependant.
|
|
28
26
|
*
|
|
29
|
-
* @category
|
|
27
|
+
* @category Server
|
|
30
28
|
*/
|
|
31
|
-
export interface Request<
|
|
29
|
+
export interface Request<Raw, Context> {
|
|
32
30
|
readonly method: string;
|
|
33
31
|
readonly url: string;
|
|
34
32
|
readonly headers: RequestHeaders;
|
|
@@ -45,7 +43,7 @@ export interface Request<RawRequest, Context> {
|
|
|
45
43
|
* For example: `express.Request` when using Express, or maybe
|
|
46
44
|
* `http.IncomingMessage` when just using Node with `http.createServer`.
|
|
47
45
|
*/
|
|
48
|
-
readonly raw:
|
|
46
|
+
readonly raw: Raw;
|
|
49
47
|
/**
|
|
50
48
|
* Context value about the incoming request, you're free to pass any information here.
|
|
51
49
|
*/
|
|
@@ -54,7 +52,7 @@ export interface Request<RawRequest, Context> {
|
|
|
54
52
|
/**
|
|
55
53
|
* The response headers that get returned from graphql-http.
|
|
56
54
|
*
|
|
57
|
-
* @category
|
|
55
|
+
* @category Server
|
|
58
56
|
*/
|
|
59
57
|
export declare type ResponseHeaders = {
|
|
60
58
|
accept?: string;
|
|
@@ -65,14 +63,14 @@ export declare type ResponseHeaders = {
|
|
|
65
63
|
* Server agnostic response body returned from `graphql-http` needing
|
|
66
64
|
* to be coerced to the server implementation in use.
|
|
67
65
|
*
|
|
68
|
-
* @category
|
|
66
|
+
* @category Server
|
|
69
67
|
*/
|
|
70
68
|
export declare type ResponseBody = string;
|
|
71
69
|
/**
|
|
72
70
|
* Server agnostic response options (ex. status and headers) returned from
|
|
73
71
|
* `graphql-http` needing to be coerced to the server implementation in use.
|
|
74
72
|
*
|
|
75
|
-
* @category
|
|
73
|
+
* @category Server
|
|
76
74
|
*/
|
|
77
75
|
export interface ResponseInit {
|
|
78
76
|
readonly status: number;
|
|
@@ -83,13 +81,13 @@ export interface ResponseInit {
|
|
|
83
81
|
* Server agnostic response returned from `graphql-http` containing the
|
|
84
82
|
* body and init options needing to be coerced to the server implementation in use.
|
|
85
83
|
*
|
|
86
|
-
* @category
|
|
84
|
+
* @category Server
|
|
87
85
|
*/
|
|
88
86
|
export declare type Response = readonly [body: ResponseBody | null, init: ResponseInit];
|
|
89
87
|
/**
|
|
90
88
|
* Checks whether the passed value is the `graphql-http` server agnostic response.
|
|
91
89
|
*
|
|
92
|
-
* @category
|
|
90
|
+
* @category Server
|
|
93
91
|
*/
|
|
94
92
|
export declare function isResponse(val: unknown): val is Response;
|
|
95
93
|
/**
|
|
@@ -102,9 +100,13 @@ export declare function isResponse(val: unknown): val is Response;
|
|
|
102
100
|
*
|
|
103
101
|
* @category Server
|
|
104
102
|
*/
|
|
105
|
-
export declare type
|
|
103
|
+
export declare type OperationContext = Record<PropertyKey, unknown> | symbol | number | string | boolean | undefined | null;
|
|
104
|
+
/** @category Server */
|
|
105
|
+
export declare type OperationArgs<Context extends OperationContext = undefined> = ExecutionArgs & {
|
|
106
|
+
contextValue?: Context;
|
|
107
|
+
};
|
|
106
108
|
/** @category Server */
|
|
107
|
-
export interface HandlerOptions<
|
|
109
|
+
export interface HandlerOptions<RequestRaw = unknown, RequestContext = unknown, Context extends OperationContext = undefined> {
|
|
108
110
|
/**
|
|
109
111
|
* The GraphQL schema on which the operations will
|
|
110
112
|
* be executed and validated against.
|
|
@@ -121,13 +123,13 @@ export interface HandlerOptions<RawRequest = unknown, Context = unknown> {
|
|
|
121
123
|
* you should do by returning a `Request` argument which will stop
|
|
122
124
|
* further execution.
|
|
123
125
|
*/
|
|
124
|
-
schema?: GraphQLSchema | ((req: Request<
|
|
126
|
+
schema?: GraphQLSchema | ((req: Request<RequestRaw, RequestContext>, args: Omit<OperationArgs<Context>, 'schema'>) => Promise<GraphQLSchema | Response> | GraphQLSchema | Response);
|
|
125
127
|
/**
|
|
126
128
|
* A value which is provided to every resolver and holds
|
|
127
129
|
* important contextual information like the currently
|
|
128
130
|
* logged in user, or access to a database.
|
|
129
131
|
*/
|
|
130
|
-
context?:
|
|
132
|
+
context?: Context | ((req: Request<RequestRaw, RequestContext>, params: RequestParams) => Promise<Context | Response> | Context | Response);
|
|
131
133
|
/**
|
|
132
134
|
* A custom GraphQL validate function allowing you to apply your
|
|
133
135
|
* own validation rules.
|
|
@@ -176,7 +178,7 @@ export interface HandlerOptions<RawRequest = unknown, Context = unknown> {
|
|
|
176
178
|
* you should do by returning a `Request` argument which will stop
|
|
177
179
|
* further execution.
|
|
178
180
|
*/
|
|
179
|
-
onSubscribe?: (req: Request<
|
|
181
|
+
onSubscribe?: (req: Request<RequestRaw, RequestContext>, params: RequestParams) => Promise<ExecutionResult | OperationArgs<Context> | readonly GraphQLError[] | Response | void> | ExecutionResult | OperationArgs<Context> | readonly GraphQLError[] | Response | void;
|
|
180
182
|
/**
|
|
181
183
|
* Executed after the operation call resolves.
|
|
182
184
|
*
|
|
@@ -190,7 +192,7 @@ export interface HandlerOptions<RawRequest = unknown, Context = unknown> {
|
|
|
190
192
|
* you should do by returning a `Request` argument which will stop
|
|
191
193
|
* further execution.
|
|
192
194
|
*/
|
|
193
|
-
onOperation?: (req: Request<
|
|
195
|
+
onOperation?: (req: Request<RequestRaw, RequestContext>, args: OperationArgs<Context>, result: ExecutionResult) => Promise<ExecutionResult | Response | void> | ExecutionResult | Response | void;
|
|
194
196
|
}
|
|
195
197
|
/**
|
|
196
198
|
* The ready-to-use handler. Simply plug it in your favourite HTTP framework
|
|
@@ -202,7 +204,7 @@ export interface HandlerOptions<RawRequest = unknown, Context = unknown> {
|
|
|
202
204
|
*
|
|
203
205
|
* @category Server
|
|
204
206
|
*/
|
|
205
|
-
export declare type Handler<
|
|
207
|
+
export declare type Handler<RequestRaw = unknown, RequestContext = unknown> = (req: Request<RequestRaw, RequestContext>) => Promise<Response>;
|
|
206
208
|
/**
|
|
207
209
|
* Makes a GraphQL over HTTP Protocol compliant server handler. The handler can
|
|
208
210
|
* be used with your favourite server library.
|
|
@@ -258,7 +260,7 @@ export declare type Handler<RawRequest = unknown, Context = unknown> = (req: Req
|
|
|
258
260
|
*
|
|
259
261
|
* @category Server
|
|
260
262
|
*/
|
|
261
|
-
export declare function createHandler<
|
|
263
|
+
export declare function createHandler<RequestRaw = unknown, RequestContext = unknown, Context extends OperationContext = undefined>(options: HandlerOptions<RequestRaw, RequestContext, Context>): Handler<RequestRaw, RequestContext>;
|
|
262
264
|
/**
|
|
263
265
|
* Request's Media-Type that the server accepts.
|
|
264
266
|
*
|
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
|
|
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
|
|
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
|
|
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
|
|
261
|
-
if (isResponse(
|
|
262
|
-
return
|
|
263
|
-
args.contextValue =
|
|
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
|
|
11
|
+
* @category Server
|
|
12
12
|
*/
|
|
13
13
|
export function isResponse(val) {
|
|
14
14
|
// TODO: make sure the contents of init match ResponseInit
|
|
@@ -88,7 +88,7 @@ export function createHandler(options) {
|
|
|
88
88
|
},
|
|
89
89
|
];
|
|
90
90
|
}
|
|
91
|
-
const acceptedMediaType = getAcceptableMediaType(req
|
|
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
|
|
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
|
|
257
|
-
if (isResponse(
|
|
258
|
-
return
|
|
259
|
-
args.contextValue =
|
|
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,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
|
+
}
|