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/LICENSE.md
CHANGED
package/README.md
CHANGED
|
@@ -5,10 +5,12 @@
|
|
|
5
5
|
|
|
6
6
|
<h6>Simple, pluggable, zero-dependency, <a href="https://graphql.github.io/graphql-over-http">GraphQL over HTTP Protocol</a> compliant server and client.</h6>
|
|
7
7
|
|
|
8
|
-
[](https://github.com/graphql/graphql-http/actions?query=workflow%3A%22Continuous+integration%22) [](https://www.npmjs.com/package/graphql-http)
|
|
9
9
|
|
|
10
10
|
<i>Need subscriptions? Try <b>[graphql-ws](https://github.com/enisdenjo/graphql-ws)</b> or <b>[graphql-sse](https://github.com/enisdenjo/graphql-sse)</b> instead!</i>
|
|
11
11
|
|
|
12
|
+
<i>Want a full-featured server? See the <b>[servers section](#servers)</b></i>!
|
|
13
|
+
|
|
12
14
|
<br />
|
|
13
15
|
</div>
|
|
14
16
|
|
|
@@ -51,34 +53,18 @@ const schema = new GraphQLSchema({
|
|
|
51
53
|
|
|
52
54
|
```js
|
|
53
55
|
import http from 'http';
|
|
54
|
-
import { createHandler } from 'graphql-http';
|
|
56
|
+
import { createHandler } from 'graphql-http/lib/use/node';
|
|
55
57
|
import { schema } from './previous-step';
|
|
56
58
|
|
|
57
|
-
// Create the GraphQL over HTTP handler
|
|
59
|
+
// Create the GraphQL over HTTP Node request handler
|
|
58
60
|
const handler = createHandler({ schema });
|
|
59
61
|
|
|
60
|
-
// Create a HTTP server using the
|
|
61
|
-
const server = http.createServer(
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
try {
|
|
67
|
-
const [body, init] = await handler({
|
|
68
|
-
url: req.url,
|
|
69
|
-
method: req.method,
|
|
70
|
-
headers: req.headers,
|
|
71
|
-
body: () =>
|
|
72
|
-
new Promise((resolve) => {
|
|
73
|
-
let body = '';
|
|
74
|
-
req.on('data', (chunk) => (body += chunk));
|
|
75
|
-
req.on('end', () => resolve(body));
|
|
76
|
-
}),
|
|
77
|
-
raw: req,
|
|
78
|
-
});
|
|
79
|
-
res.writeHead(init.status, init.statusText, init.headers).end(body);
|
|
80
|
-
} catch (err) {
|
|
81
|
-
res.writeHead(500).end(err.message);
|
|
62
|
+
// Create a HTTP server using the listner on `/graphql`
|
|
63
|
+
const server = http.createServer((req, res) => {
|
|
64
|
+
if (req.url.startsWith('/graphql')) {
|
|
65
|
+
handler(req, res);
|
|
66
|
+
} else {
|
|
67
|
+
res.writeHead(404).end();
|
|
82
68
|
}
|
|
83
69
|
});
|
|
84
70
|
|
|
@@ -98,10 +84,10 @@ $ openssl req -x509 -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' \
|
|
|
98
84
|
```js
|
|
99
85
|
import fs from 'fs';
|
|
100
86
|
import http2 from 'http2';
|
|
101
|
-
import { createHandler } from 'graphql-http';
|
|
87
|
+
import { createHandler } from 'graphql-http/lib/use/node';
|
|
102
88
|
import { schema } from './previous-step';
|
|
103
89
|
|
|
104
|
-
// Create the GraphQL over HTTP handler
|
|
90
|
+
// Create the GraphQL over HTTP Node request handler
|
|
105
91
|
const handler = createHandler({ schema });
|
|
106
92
|
|
|
107
93
|
// Create a HTTP/2 server using the handler on `/graphql`
|
|
@@ -110,27 +96,11 @@ const server = http2.createSecureServer(
|
|
|
110
96
|
key: fs.readFileSync('localhost-privkey.pem'),
|
|
111
97
|
cert: fs.readFileSync('localhost-cert.pem'),
|
|
112
98
|
},
|
|
113
|
-
|
|
114
|
-
if (
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
try {
|
|
119
|
-
const [body, init] = await handler({
|
|
120
|
-
url: req.url,
|
|
121
|
-
method: req.method,
|
|
122
|
-
headers: req.headers,
|
|
123
|
-
body: () =>
|
|
124
|
-
new Promise((resolve) => {
|
|
125
|
-
let body = '';
|
|
126
|
-
req.on('data', (chunk) => (body += chunk));
|
|
127
|
-
req.on('end', () => resolve(body));
|
|
128
|
-
}),
|
|
129
|
-
raw: req,
|
|
130
|
-
});
|
|
131
|
-
res.writeHead(init.status, init.statusText, init.headers).end(body);
|
|
132
|
-
} catch (err) {
|
|
133
|
-
res.writeHead(500).end(err.message);
|
|
99
|
+
(req, res) => {
|
|
100
|
+
if (req.url.startsWith('/graphql')) {
|
|
101
|
+
handler(req, res);
|
|
102
|
+
} else {
|
|
103
|
+
res.writeHead(404).end();
|
|
134
104
|
}
|
|
135
105
|
},
|
|
136
106
|
);
|
|
@@ -143,35 +113,15 @@ console.log('Listening to port 4000');
|
|
|
143
113
|
|
|
144
114
|
```js
|
|
145
115
|
import express from 'express'; // yarn add express
|
|
146
|
-
import { createHandler } from 'graphql-http';
|
|
116
|
+
import { createHandler } from 'graphql-http/lib/use/express';
|
|
147
117
|
import { schema } from './previous-step';
|
|
148
118
|
|
|
149
|
-
// Create
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
// Create an express app serving all methods on `/graphql`
|
|
119
|
+
// Create a express instance serving all methods on `/graphql`
|
|
120
|
+
// where the GraphQL over HTTP express request handler is
|
|
153
121
|
const app = express();
|
|
154
|
-
app.
|
|
155
|
-
try {
|
|
156
|
-
const [body, init] = await handler({
|
|
157
|
-
url: req.url,
|
|
158
|
-
method: req.method,
|
|
159
|
-
headers: req.headers,
|
|
160
|
-
body: () =>
|
|
161
|
-
new Promise((resolve) => {
|
|
162
|
-
let body = '';
|
|
163
|
-
req.on('data', (chunk) => (body += chunk));
|
|
164
|
-
req.on('end', () => resolve(body));
|
|
165
|
-
}),
|
|
166
|
-
raw: req,
|
|
167
|
-
});
|
|
168
|
-
res.writeHead(init.status, init.statusText, init.headers).end(body);
|
|
169
|
-
} catch (err) {
|
|
170
|
-
res.writeHead(500).end(err.message);
|
|
171
|
-
}
|
|
172
|
-
});
|
|
122
|
+
app.all('/graphql', createHandler({ schema }));
|
|
173
123
|
|
|
174
|
-
app.listen(4000);
|
|
124
|
+
app.listen({ port: 4000 });
|
|
175
125
|
console.log('Listening to port 4000');
|
|
176
126
|
```
|
|
177
127
|
|
|
@@ -179,30 +129,15 @@ console.log('Listening to port 4000');
|
|
|
179
129
|
|
|
180
130
|
```js
|
|
181
131
|
import Fastify from 'fastify'; // yarn add fastify
|
|
182
|
-
import { createHandler } from 'graphql-http';
|
|
132
|
+
import { createHandler } from 'graphql-http/lib/use/fastify';
|
|
183
133
|
import { schema } from './previous-step';
|
|
184
134
|
|
|
185
|
-
// Create the GraphQL over HTTP handler
|
|
186
|
-
const handler = createHandler({ schema });
|
|
187
|
-
|
|
188
135
|
// Create a fastify instance serving all methods on `/graphql`
|
|
136
|
+
// where the GraphQL over HTTP fastify request handler is
|
|
189
137
|
const fastify = Fastify();
|
|
190
|
-
fastify.all('/graphql',
|
|
191
|
-
try {
|
|
192
|
-
const [body, init] = await handler({
|
|
193
|
-
url: req.url,
|
|
194
|
-
method: req.method,
|
|
195
|
-
headers: req.headers,
|
|
196
|
-
body: req.body, // fastify reads the body for you
|
|
197
|
-
raw: req,
|
|
198
|
-
});
|
|
199
|
-
res.writeHead(init.status, init.statusText, init.headers).end(body);
|
|
200
|
-
} catch (err) {
|
|
201
|
-
res.writeHead(500).end(err.message);
|
|
202
|
-
}
|
|
203
|
-
});
|
|
138
|
+
fastify.all('/graphql', createHandler({ schema }));
|
|
204
139
|
|
|
205
|
-
fastify.listen(4000);
|
|
140
|
+
fastify.listen({ port: 4000 });
|
|
206
141
|
console.log('Listening to port 4000');
|
|
207
142
|
```
|
|
208
143
|
|
|
@@ -210,37 +145,49 @@ console.log('Listening to port 4000');
|
|
|
210
145
|
|
|
211
146
|
```ts
|
|
212
147
|
import { serve } from 'https://deno.land/std@0.151.0/http/server.ts';
|
|
213
|
-
import { createHandler } from 'https://esm.sh/graphql-http';
|
|
148
|
+
import { createHandler } from 'https://esm.sh/graphql-http/lib/use/fetch';
|
|
214
149
|
import { schema } from './previous-step';
|
|
215
150
|
|
|
216
|
-
// Create the GraphQL over HTTP handler
|
|
217
|
-
const handler = createHandler
|
|
151
|
+
// Create the GraphQL over HTTP native fetch handler
|
|
152
|
+
const handler = createHandler({ schema });
|
|
218
153
|
|
|
219
154
|
// Start serving on `/graphql` using the handler
|
|
220
155
|
await serve(
|
|
221
|
-
|
|
156
|
+
(req: Request) => {
|
|
222
157
|
const [path, _search] = req.url.split('?');
|
|
223
|
-
if (
|
|
224
|
-
return
|
|
158
|
+
if (path.endsWith('/graphql')) {
|
|
159
|
+
return handler(req);
|
|
160
|
+
} else {
|
|
161
|
+
return new Response(null, { status: 404 });
|
|
225
162
|
}
|
|
226
|
-
|
|
227
|
-
const headers: Record<string, string> = {};
|
|
228
|
-
req.headers.forEach((value, key) => (headers[key] = value));
|
|
229
|
-
const [body, init] = await handler({
|
|
230
|
-
url: req.url,
|
|
231
|
-
method: req.method,
|
|
232
|
-
headers,
|
|
233
|
-
body: () => req.text(),
|
|
234
|
-
raw: req,
|
|
235
|
-
});
|
|
236
|
-
return new Response(body, init);
|
|
237
163
|
},
|
|
238
164
|
{
|
|
239
|
-
port: 4000,
|
|
165
|
+
port: 4000, // Listening to port 4000
|
|
240
166
|
},
|
|
241
167
|
);
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
##### With [`Bun`](https://bun.sh/)
|
|
242
171
|
|
|
243
|
-
|
|
172
|
+
```js
|
|
173
|
+
import { createHandler } from 'graphql-http/lib/use/fetch'; // bun install graphql-http
|
|
174
|
+
import { schema } from './previous-step';
|
|
175
|
+
|
|
176
|
+
// Create the GraphQL over HTTP native fetch handler
|
|
177
|
+
const handler = createHandler({ schema });
|
|
178
|
+
|
|
179
|
+
// Start serving on `/graphql` using the handler
|
|
180
|
+
export default {
|
|
181
|
+
port: 4000, // Listening to port 4000
|
|
182
|
+
fetch(req) {
|
|
183
|
+
const [path, _search] = req.url.split('?');
|
|
184
|
+
if (path.endsWith('/graphql')) {
|
|
185
|
+
return handler(req);
|
|
186
|
+
} else {
|
|
187
|
+
return new Response(null, { status: 404 });
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
};
|
|
244
191
|
```
|
|
245
192
|
|
|
246
193
|
#### Use the client
|
|
@@ -555,7 +502,7 @@ const client = createClient({
|
|
|
555
502
|
<summary><a href="#deno-client">🔗</a> Client usage in Deno</summary>
|
|
556
503
|
|
|
557
504
|
```js
|
|
558
|
-
import { createClient } from 'graphql-http';
|
|
505
|
+
import { createClient } from 'https://esm.sh/graphql-http';
|
|
559
506
|
|
|
560
507
|
const client = createClient({
|
|
561
508
|
url: 'http://deno.earth:4000/graphql',
|
|
@@ -566,6 +513,43 @@ const client = createClient({
|
|
|
566
513
|
|
|
567
514
|
</details>
|
|
568
515
|
|
|
516
|
+
<details id="bun-client">
|
|
517
|
+
<summary><a href="#bun-client">🔗</a> Client usage in Bun</summary>
|
|
518
|
+
|
|
519
|
+
```js
|
|
520
|
+
import { createClient } from 'graphql-http'; // bun install graphql-http
|
|
521
|
+
|
|
522
|
+
const client = createClient({
|
|
523
|
+
url: 'http://bun.bread:4000/graphql',
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
// consider other recipes for usage inspiration
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
</details>
|
|
530
|
+
|
|
531
|
+
<details id="migrating-express-grpahql">
|
|
532
|
+
<summary><a href="#migrating-express-grpahql">🔗</a> Server handler migration from <a href="https://github.com/graphql/express-graphql">express-graphql</a></summary>
|
|
533
|
+
|
|
534
|
+
```diff
|
|
535
|
+
import express from 'express';
|
|
536
|
+
import { schema } from './my-graphql-schema';
|
|
537
|
+
|
|
538
|
+
-import { graphqlHTTP } from 'express-graphql';
|
|
539
|
+
+import { createHandler } from 'graphql-http/lib/use/express';
|
|
540
|
+
|
|
541
|
+
const app = express();
|
|
542
|
+
|
|
543
|
+
app.use(
|
|
544
|
+
'/graphql',
|
|
545
|
+
- graphqlHTTP({ schema }),
|
|
546
|
+
+ createHandler({ schema }),
|
|
547
|
+
);
|
|
548
|
+
|
|
549
|
+
app.listen(4000);
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
</details>
|
|
569
553
|
<details id="auth">
|
|
570
554
|
<summary><a href="#auth">🔗</a> Server handler usage with authentication</summary>
|
|
571
555
|
|
|
@@ -735,6 +719,23 @@ for (const audit of serverAudits({
|
|
|
735
719
|
|
|
736
720
|
</details>
|
|
737
721
|
|
|
722
|
+
## Only [GraphQL over HTTP](https://graphql.github.io/graphql-over-http/)
|
|
723
|
+
|
|
724
|
+
This is the official [GraphQL over HTTP spec](https://graphql.github.io/graphql-over-http/) reference implementation and as such follows the specification strictly without any additional features (like file uploads, @stream/@defer directives and subscriptions).
|
|
725
|
+
|
|
726
|
+
Having said this, graphql-http is mostly aimed for library authors and simple server setups, where the requirements are exact to what the aforementioned spec offers.
|
|
727
|
+
|
|
728
|
+
## [Servers](/implementations)
|
|
729
|
+
|
|
730
|
+
If you want a feature-full server with bleeding edge technologies, you're recommended to use one of the following.
|
|
731
|
+
|
|
732
|
+
| Name | Audit |
|
|
733
|
+
| -------------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
734
|
+
| [graphql-yoga](https://www.the-guild.dev/graphql/yoga-server) | [✅ Fully compliant](/implementations/graphql-yoga/README.md) |
|
|
735
|
+
| [apollo-server](https://www.the-guild.dev/graphql/yoga-server) | [⚠️ Partially compliant](/implementations/apollo-server/README.md) |
|
|
736
|
+
| [mercurius](https://mercurius.dev) | [⚠️ Partially compliant](/implementations/mercurius/README.md) |
|
|
737
|
+
| [graphql-helix](https://www.graphql-helix.com/) | [⚠️ Partially compliant](/implementations/graphql-helix/README.md) |
|
|
738
|
+
|
|
738
739
|
## [Documentation](docs/)
|
|
739
740
|
|
|
740
741
|
Check the [docs folder](docs/) out for [TypeDoc](https://typedoc.org) generated documentation.
|
|
@@ -743,6 +744,14 @@ Check the [docs folder](docs/) out for [TypeDoc](https://typedoc.org) generated
|
|
|
743
744
|
|
|
744
745
|
Inspect audits of other implementations in the [implementations folder](implementations/). Adding your implementation is very welcome!
|
|
745
746
|
|
|
746
|
-
##
|
|
747
|
+
## Want to help?
|
|
748
|
+
|
|
749
|
+
File a bug, contribute with code, or improve documentation? Read up on our guidelines below and drive development with `yarn test --watch` away!
|
|
750
|
+
|
|
751
|
+
This repository is managed by EasyCLA. Project participants must sign the free [GraphQL Specification Membership agreement](https://preview-spec-membership.graphql.org) before making a contribution. You only need to do this one time, and it can be signed by [individual contributors](http://individual-spec-membership.graphql.org/) or their [employers](http://corporate-spec-membership.graphql.org/).
|
|
752
|
+
|
|
753
|
+
To initiate the signature process please open a PR against this repo. The EasyCLA bot will block the merge if we still need a membership agreement from you.
|
|
754
|
+
|
|
755
|
+
You can find [detailed information here](https://github.com/graphql/graphql-wg/tree/main/membership). If you have issues, please email [operations@graphql.org](mailto:operations@graphql.org).
|
|
747
756
|
|
|
748
|
-
|
|
757
|
+
If your company benefits from GraphQL and you would like to provide essential financial support for the systems and people that power our community, please also consider membership in the [GraphQL Foundation](https://foundation.graphql.org/join).
|
package/lib/audits/server.js
CHANGED
|
@@ -87,24 +87,27 @@ function serverAudits(opts) {
|
|
|
87
87
|
throw 'Body is not UTF-8 encoded';
|
|
88
88
|
}
|
|
89
89
|
}),
|
|
90
|
-
(0, utils_1.audit)('MUST accept
|
|
90
|
+
(0, utils_1.audit)('MUST accept utf-8 encoding', async () => {
|
|
91
91
|
const url = new URL(opts.url);
|
|
92
92
|
url.searchParams.set('query', '{ __typename }');
|
|
93
93
|
const res = await fetchFn(url.toString(), {
|
|
94
94
|
headers: {
|
|
95
|
-
|
|
95
|
+
'content-type': 'application/json; charset=utf-8',
|
|
96
96
|
},
|
|
97
97
|
});
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
98
|
+
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
99
|
+
(0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('utf-8');
|
|
100
|
+
}),
|
|
101
|
+
(0, utils_1.audit)('MUST assume utf-8 if encoding is unspecified', async () => {
|
|
102
|
+
const url = new URL(opts.url);
|
|
103
|
+
url.searchParams.set('query', '{ __typename }');
|
|
104
|
+
const res = await fetchFn(url.toString(), {
|
|
105
|
+
headers: {
|
|
106
|
+
'content-type': 'application/json',
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
110
|
+
(0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('utf-8');
|
|
108
111
|
}),
|
|
109
112
|
// Request
|
|
110
113
|
(0, utils_1.audit)('MUST accept POST requests', async () => {
|
package/lib/audits/server.mjs
CHANGED
|
@@ -84,24 +84,27 @@ export function serverAudits(opts) {
|
|
|
84
84
|
throw 'Body is not UTF-8 encoded';
|
|
85
85
|
}
|
|
86
86
|
}),
|
|
87
|
-
audit('MUST accept
|
|
87
|
+
audit('MUST accept utf-8 encoding', async () => {
|
|
88
88
|
const url = new URL(opts.url);
|
|
89
89
|
url.searchParams.set('query', '{ __typename }');
|
|
90
90
|
const res = await fetchFn(url.toString(), {
|
|
91
91
|
headers: {
|
|
92
|
-
|
|
92
|
+
'content-type': 'application/json; charset=utf-8',
|
|
93
93
|
},
|
|
94
94
|
});
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
95
|
+
assert('Status code', res.status).toBe(200);
|
|
96
|
+
assert('Content-Type header', res.headers.get('content-type')).toContain('utf-8');
|
|
97
|
+
}),
|
|
98
|
+
audit('MUST assume utf-8 if encoding is unspecified', async () => {
|
|
99
|
+
const url = new URL(opts.url);
|
|
100
|
+
url.searchParams.set('query', '{ __typename }');
|
|
101
|
+
const res = await fetchFn(url.toString(), {
|
|
102
|
+
headers: {
|
|
103
|
+
'content-type': 'application/json',
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
assert('Status code', res.status).toBe(200);
|
|
107
|
+
assert('Content-Type header', res.headers.get('content-type')).toContain('utf-8');
|
|
105
108
|
}),
|
|
106
109
|
// Request
|
|
107
110
|
audit('MUST accept POST requests', async () => {
|
package/lib/audits/utils.d.mts
CHANGED
package/lib/audits/utils.d.ts
CHANGED
package/lib/handler.d.mts
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
|
*
|