graphql-http 1.17.1 → 1.19.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/README.md +17 -1
- package/lib/audits/common.d.mts +1 -1
- package/lib/audits/common.d.ts +1 -1
- package/lib/audits/render.js +15 -0
- package/lib/audits/render.mjs +15 -0
- package/lib/audits/server.js +42 -172
- package/lib/audits/server.mjs +42 -172
- package/lib/audits/utils.js +6 -3
- package/lib/audits/utils.mjs +6 -3
- package/lib/handler.d.mts +20 -3
- package/lib/handler.d.ts +20 -3
- package/lib/handler.js +36 -14
- package/lib/handler.mjs +37 -15
- package/lib/use/express.js +1 -18
- package/lib/use/express.mjs +1 -18
- package/lib/use/fastify.js +1 -19
- package/lib/use/fastify.mjs +1 -19
- package/lib/use/fetch.d.mts +1 -1
- package/lib/use/fetch.d.ts +1 -1
- package/lib/use/fetch.js +2 -22
- package/lib/use/fetch.mjs +2 -22
- package/lib/use/http.d.mts +1 -1
- package/lib/use/http.d.ts +1 -1
- package/lib/use/http.js +2 -19
- package/lib/use/http.mjs +2 -19
- package/lib/use/http2.d.mts +1 -1
- package/lib/use/http2.d.ts +1 -1
- package/lib/use/http2.js +2 -19
- package/lib/use/http2.mjs +2 -19
- package/lib/use/koa.js +0 -14
- package/lib/use/koa.mjs +0 -14
- package/lib/use/node.d.mts +1 -1
- package/lib/use/node.d.ts +1 -1
- package/lib/use/node.js +1 -1
- package/lib/use/node.mjs +1 -1
- package/lib/use/uWebSockets.d.mts +36 -0
- package/lib/use/uWebSockets.d.ts +36 -0
- package/lib/use/uWebSockets.js +84 -0
- package/lib/use/uWebSockets.mjs +80 -0
- package/lib/utils.d.mts +2 -0
- package/lib/utils.d.ts +2 -0
- package/lib/utils.js +15 -1
- package/lib/utils.mjs +13 -0
- package/package.json +30 -25
- package/umd/graphql-http-audits.js +63 -175
- package/umd/graphql-http-audits.min.js +1 -1
- package/umd/graphql-http-audits.min.js.gz +0 -0
package/README.md
CHANGED
|
@@ -158,6 +158,21 @@ app.listen({ port: 4000 });
|
|
|
158
158
|
console.log('Listening to port 4000');
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
+
##### With [`uWebSockets.js`](https://github.com/uNetworking/uWebSockets.js)
|
|
162
|
+
|
|
163
|
+
```js
|
|
164
|
+
import uWS from 'uWebSockets.js'; // yarn add uWebSockets.js@uNetworking/uWebSockets.js#<version>
|
|
165
|
+
import { createHandler } from 'graphql-http/lib/use/uWebSockets';
|
|
166
|
+
import { schema } from './previous-step';
|
|
167
|
+
|
|
168
|
+
uWS
|
|
169
|
+
.App()
|
|
170
|
+
.any('/graphql', createHandler({ schema }))
|
|
171
|
+
.listen(4000, () => {
|
|
172
|
+
console.log('Listening to port 4000');
|
|
173
|
+
});
|
|
174
|
+
```
|
|
175
|
+
|
|
161
176
|
##### With [`Deno`](https://deno.land/)
|
|
162
177
|
|
|
163
178
|
```ts
|
|
@@ -768,7 +783,7 @@ Put the above contents in a file and run it with `deno test --allow-net`.
|
|
|
768
783
|
|
|
769
784
|
## Only [GraphQL over HTTP](https://graphql.github.io/graphql-over-http/)
|
|
770
785
|
|
|
771
|
-
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).
|
|
786
|
+
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 playgrounds or GUIs, file uploads, @stream/@defer directives and subscriptions).
|
|
772
787
|
|
|
773
788
|
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.
|
|
774
789
|
|
|
@@ -788,6 +803,7 @@ Their compliance with the [GraphQL over HTTP spec](https://graphql.github.io/gra
|
|
|
788
803
|
| [graphql-helix](https://www.graphql-helix.com) | [✅ Compliant](/implementations/graphql-helix/README.md) |
|
|
789
804
|
| [graphql-yoga](https://www.the-guild.dev/graphql/yoga-server) | [✅ Compliant](/implementations/graphql-yoga/README.md) |
|
|
790
805
|
| [hotchocolate](https://chillicream.com/docs/hotchocolate) | [✅ Compliant](/implementations/hotchocolate/README.md) |
|
|
806
|
+
| [lighthouse](https://lighthouse-php.com) | [✅ Compliant](/implementations/lighthouse/README.md) |
|
|
791
807
|
| [pioneer](https://pioneer.dexclaimation.com) | [✅ Compliant](/implementations/pioneer/README.md) |
|
|
792
808
|
| [postgraphile](https://www.graphile.org/postgraphile) | [✅ Compliant](/implementations/postgraphile/README.md) |
|
|
793
809
|
<!-- prettier-ignore-end -->
|
package/lib/audits/common.d.mts
CHANGED
package/lib/audits/common.d.ts
CHANGED
package/lib/audits/render.js
CHANGED
|
@@ -11,6 +11,7 @@ async function renderAuditResultsToHTML(results) {
|
|
|
11
11
|
const grouped = {
|
|
12
12
|
total: 0,
|
|
13
13
|
ok: [],
|
|
14
|
+
notice: [],
|
|
14
15
|
warn: [],
|
|
15
16
|
error: [],
|
|
16
17
|
};
|
|
@@ -33,6 +34,9 @@ async function renderAuditResultsToHTML(results) {
|
|
|
33
34
|
if (grouped.ok.length) {
|
|
34
35
|
report += `<li><span style="font-family: monospace">✅</span> <b>${grouped.ok.length}</b> pass</li>\n`;
|
|
35
36
|
}
|
|
37
|
+
if (grouped.notice.length) {
|
|
38
|
+
report += `<li><span style="font-family: monospace">💡</span> <b>${grouped.notice.length}</b> notices (suggestions)</li>\n`;
|
|
39
|
+
}
|
|
36
40
|
if (grouped.warn.length) {
|
|
37
41
|
// TODO: warning sign is rendered as "⚠️" in markdown instead of the emoji
|
|
38
42
|
report += `<li><span style="font-family: monospace">⚠️</span> <b>${grouped.warn.length}</b> warnings (optional)</li>\n`;
|
|
@@ -51,6 +55,17 @@ async function renderAuditResultsToHTML(results) {
|
|
|
51
55
|
report += '</ol>\n';
|
|
52
56
|
report += '\n';
|
|
53
57
|
}
|
|
58
|
+
if (grouped.notice.length) {
|
|
59
|
+
report += `<h2>Notices</h2>\n`;
|
|
60
|
+
report +=
|
|
61
|
+
'The server <i>MAY</i> support these, but are truly optional. These are suggestions following recommended conventions.\n';
|
|
62
|
+
report += '<ol>\n';
|
|
63
|
+
for (const [, result] of grouped.notice.entries()) {
|
|
64
|
+
report += await printAuditFail(result);
|
|
65
|
+
}
|
|
66
|
+
report += '</ol>\n';
|
|
67
|
+
report += '\n';
|
|
68
|
+
}
|
|
54
69
|
if (grouped.warn.length) {
|
|
55
70
|
report += `<h2>Warnings</h2>\n`;
|
|
56
71
|
report += 'The server <i>SHOULD</i> support these, but is not required.\n';
|
package/lib/audits/render.mjs
CHANGED
|
@@ -8,6 +8,7 @@ export async function renderAuditResultsToHTML(results) {
|
|
|
8
8
|
const grouped = {
|
|
9
9
|
total: 0,
|
|
10
10
|
ok: [],
|
|
11
|
+
notice: [],
|
|
11
12
|
warn: [],
|
|
12
13
|
error: [],
|
|
13
14
|
};
|
|
@@ -30,6 +31,9 @@ export async function renderAuditResultsToHTML(results) {
|
|
|
30
31
|
if (grouped.ok.length) {
|
|
31
32
|
report += `<li><span style="font-family: monospace">✅</span> <b>${grouped.ok.length}</b> pass</li>\n`;
|
|
32
33
|
}
|
|
34
|
+
if (grouped.notice.length) {
|
|
35
|
+
report += `<li><span style="font-family: monospace">💡</span> <b>${grouped.notice.length}</b> notices (suggestions)</li>\n`;
|
|
36
|
+
}
|
|
33
37
|
if (grouped.warn.length) {
|
|
34
38
|
// TODO: warning sign is rendered as "⚠️" in markdown instead of the emoji
|
|
35
39
|
report += `<li><span style="font-family: monospace">⚠️</span> <b>${grouped.warn.length}</b> warnings (optional)</li>\n`;
|
|
@@ -48,6 +52,17 @@ export async function renderAuditResultsToHTML(results) {
|
|
|
48
52
|
report += '</ol>\n';
|
|
49
53
|
report += '\n';
|
|
50
54
|
}
|
|
55
|
+
if (grouped.notice.length) {
|
|
56
|
+
report += `<h2>Notices</h2>\n`;
|
|
57
|
+
report +=
|
|
58
|
+
'The server <i>MAY</i> support these, but are truly optional. These are suggestions following recommended conventions.\n';
|
|
59
|
+
report += '<ol>\n';
|
|
60
|
+
for (const [, result] of grouped.notice.entries()) {
|
|
61
|
+
report += await printAuditFail(result);
|
|
62
|
+
}
|
|
63
|
+
report += '</ol>\n';
|
|
64
|
+
report += '\n';
|
|
65
|
+
}
|
|
51
66
|
if (grouped.warn.length) {
|
|
52
67
|
report += `<h2>Warnings</h2>\n`;
|
|
53
68
|
report += 'The server <i>SHOULD</i> support these, but is not required.\n';
|
package/lib/audits/server.js
CHANGED
|
@@ -57,9 +57,13 @@ function serverAudits(opts) {
|
|
|
57
57
|
(0, utils_1.ressert)(res).header('content-type').toContain('application/json');
|
|
58
58
|
}),
|
|
59
59
|
(0, utils_1.audit)('80D8', 'SHOULD assume application/json content-type when accept is missing', async () => {
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
const res = await fetchFn(await getUrl(opts.url), {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
headers: {
|
|
63
|
+
'content-type': 'application/json',
|
|
64
|
+
},
|
|
65
|
+
body: JSON.stringify({ query: '{ __typename }' }),
|
|
66
|
+
});
|
|
63
67
|
(0, utils_1.ressert)(res).status.toBe(200);
|
|
64
68
|
(0, utils_1.ressert)(res).header('content-type').toContain('application/json');
|
|
65
69
|
}),
|
|
@@ -130,7 +134,7 @@ function serverAudits(opts) {
|
|
|
130
134
|
(0, utils_1.ressert)(res).status.toBeBetween(400, 499);
|
|
131
135
|
}),
|
|
132
136
|
// Request POST
|
|
133
|
-
(0, utils_1.audit)('9ABE', '
|
|
137
|
+
(0, utils_1.audit)('9ABE', 'MAY respond with 4xx status code if content-type is not supplied on POST requests', async () => {
|
|
134
138
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
135
139
|
method: 'POST',
|
|
136
140
|
});
|
|
@@ -144,23 +148,15 @@ function serverAudits(opts) {
|
|
|
144
148
|
});
|
|
145
149
|
(0, utils_1.ressert)(res).status.toBe(200);
|
|
146
150
|
}),
|
|
147
|
-
(0, utils_1.audit)('
|
|
148
|
-
var _a;
|
|
151
|
+
(0, utils_1.audit)('A5BF', 'MAY use 400 status code when request body is missing on POST', async () => {
|
|
149
152
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
150
153
|
method: 'POST',
|
|
151
154
|
headers: { 'content-type': 'application/json' },
|
|
152
155
|
});
|
|
153
|
-
|
|
154
|
-
await (0, utils_1.ressert)(res).bodyAsExecutionResult.toHaveProperty('errors');
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
(0, utils_1.ressert)(res).status.toBe(400);
|
|
158
|
-
}
|
|
156
|
+
(0, utils_1.ressert)(res).status.toBe(400);
|
|
159
157
|
}),
|
|
160
158
|
// Request Parameters
|
|
161
|
-
(0, utils_1.audit)(
|
|
162
|
-
// TODO: convert to MUST after watershed
|
|
163
|
-
'6610', 'SHOULD use 400 status code on missing {query} parameter when accepting application/graphql-response+json', async () => {
|
|
159
|
+
(0, utils_1.audit)('423L', 'MAY use 400 status code on missing {query} parameter', async () => {
|
|
164
160
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
165
161
|
method: 'POST',
|
|
166
162
|
headers: {
|
|
@@ -171,26 +167,11 @@ function serverAudits(opts) {
|
|
|
171
167
|
});
|
|
172
168
|
(0, utils_1.ressert)(res).status.toBe(400);
|
|
173
169
|
}),
|
|
174
|
-
(0, utils_1.audit)(
|
|
170
|
+
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid, index) => (0, utils_1.audit)(`LKJ${index}`, `MAY use 400 status code on ${(0, utils_1.extendedTypeof)(invalid)} {query} parameter`, async () => {
|
|
175
171
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
176
172
|
method: 'POST',
|
|
177
173
|
headers: {
|
|
178
174
|
'content-type': 'application/json',
|
|
179
|
-
accept: 'application/json',
|
|
180
|
-
},
|
|
181
|
-
body: JSON.stringify({ notquery: '{ __typename }' }),
|
|
182
|
-
});
|
|
183
|
-
(0, utils_1.ressert)(res).status.toBe(200);
|
|
184
|
-
await (0, utils_1.ressert)(res).bodyAsExecutionResult.toHaveProperty('errors');
|
|
185
|
-
}),
|
|
186
|
-
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid, index) => (0, utils_1.audit)(`4F5${index}`,
|
|
187
|
-
// TODO: convert to MUST after watershed
|
|
188
|
-
`SHOULD use 400 status code on ${(0, utils_1.extendedTypeof)(invalid)} {query} parameter when accepting application/graphql-response+json`, async () => {
|
|
189
|
-
const res = await fetchFn(await getUrl(opts.url), {
|
|
190
|
-
method: 'POST',
|
|
191
|
-
headers: {
|
|
192
|
-
'content-type': 'application/json',
|
|
193
|
-
accept: 'application/graphql-response+json',
|
|
194
175
|
},
|
|
195
176
|
body: JSON.stringify({
|
|
196
177
|
query: invalid,
|
|
@@ -198,20 +179,6 @@ function serverAudits(opts) {
|
|
|
198
179
|
});
|
|
199
180
|
(0, utils_1.ressert)(res).status.toBe(400);
|
|
200
181
|
})),
|
|
201
|
-
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid, index) => (0, utils_1.audit)(`9FE${index}`, `SHOULD use 200 status code with errors field on ${(0, utils_1.extendedTypeof)(invalid)} {query} parameter when accepting application/json`, async () => {
|
|
202
|
-
const res = await fetchFn(await getUrl(opts.url), {
|
|
203
|
-
method: 'POST',
|
|
204
|
-
headers: {
|
|
205
|
-
'content-type': 'application/json',
|
|
206
|
-
accept: 'application/json',
|
|
207
|
-
},
|
|
208
|
-
body: JSON.stringify({
|
|
209
|
-
query: invalid,
|
|
210
|
-
}),
|
|
211
|
-
});
|
|
212
|
-
(0, utils_1.ressert)(res).status.toBe(200);
|
|
213
|
-
await (0, utils_1.ressert)(res).bodyAsExecutionResult.toHaveProperty('errors');
|
|
214
|
-
})),
|
|
215
182
|
(0, utils_1.audit)(
|
|
216
183
|
// TODO: convert to MUST after watershed
|
|
217
184
|
'34A2', 'SHOULD allow string {query} parameter when accepting application/graphql-response+json', async () => {
|
|
@@ -241,14 +208,11 @@ function serverAudits(opts) {
|
|
|
241
208
|
(0, utils_1.ressert)(res).status.toBe(200);
|
|
242
209
|
await (0, utils_1.ressert)(res).bodyAsExecutionResult.notToHaveProperty('errors');
|
|
243
210
|
}),
|
|
244
|
-
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid, index) => (0, utils_1.audit)(`
|
|
245
|
-
// TODO: convert to MUST after watershed
|
|
246
|
-
`SHOULD use 400 status code on ${(0, utils_1.extendedTypeof)(invalid)} {operationName} parameter when accepting application/graphql-response+json`, async () => {
|
|
211
|
+
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid, index) => (0, utils_1.audit)(`6C0${index}`, `MAY use 400 status code on ${(0, utils_1.extendedTypeof)(invalid)} {operationName} parameter`, async () => {
|
|
247
212
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
248
213
|
method: 'POST',
|
|
249
214
|
headers: {
|
|
250
215
|
'content-type': 'application/json',
|
|
251
|
-
accept: 'application/graphql-response+json',
|
|
252
216
|
},
|
|
253
217
|
body: JSON.stringify({
|
|
254
218
|
operationName: invalid,
|
|
@@ -257,21 +221,6 @@ function serverAudits(opts) {
|
|
|
257
221
|
});
|
|
258
222
|
(0, utils_1.ressert)(res).status.toBe(400);
|
|
259
223
|
})),
|
|
260
|
-
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid, index) => (0, utils_1.audit)(`FB9${index}`, `SHOULD use 200 status code with errors field on ${(0, utils_1.extendedTypeof)(invalid)} {operationName} parameter when accepting application/json`, async () => {
|
|
261
|
-
const res = await fetchFn(await getUrl(opts.url), {
|
|
262
|
-
method: 'POST',
|
|
263
|
-
headers: {
|
|
264
|
-
'content-type': 'application/json',
|
|
265
|
-
accept: 'application/json',
|
|
266
|
-
},
|
|
267
|
-
body: JSON.stringify({
|
|
268
|
-
operationName: invalid,
|
|
269
|
-
query: '{ __typename }',
|
|
270
|
-
}),
|
|
271
|
-
});
|
|
272
|
-
(0, utils_1.ressert)(res).status.toBe(200);
|
|
273
|
-
await (0, utils_1.ressert)(res).bodyAsExecutionResult.toHaveProperty('errors');
|
|
274
|
-
})),
|
|
275
224
|
(0, utils_1.audit)(
|
|
276
225
|
// TODO: convert to MUST after watershed
|
|
277
226
|
'8161', 'SHOULD allow string {operationName} parameter when accepting application/graphql-response+json', async () => {
|
|
@@ -337,14 +286,11 @@ function serverAudits(opts) {
|
|
|
337
286
|
await (0, utils_1.ressert)(res).bodyAsExecutionResult.notToHaveProperty('errors');
|
|
338
287
|
}),
|
|
339
288
|
]),
|
|
340
|
-
...['string', 0, false, ['array']].map((invalid, index) => (0, utils_1.audit)(`
|
|
341
|
-
// TODO: convert to MUST after watershed
|
|
342
|
-
`SHOULD use 400 status code on ${(0, utils_1.extendedTypeof)(invalid)} {variables} parameter when accepting application/graphql-response+json`, async () => {
|
|
289
|
+
...['string', 0, false, ['array']].map((invalid, index) => (0, utils_1.audit)(`476${index}`, `MAY use 400 status code on ${(0, utils_1.extendedTypeof)(invalid)} {variables} parameter`, async () => {
|
|
343
290
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
344
291
|
method: 'POST',
|
|
345
292
|
headers: {
|
|
346
293
|
'content-type': 'application/json',
|
|
347
|
-
accept: 'application/graphql-response+json',
|
|
348
294
|
},
|
|
349
295
|
body: JSON.stringify({
|
|
350
296
|
query: '{ __typename }',
|
|
@@ -353,21 +299,6 @@ function serverAudits(opts) {
|
|
|
353
299
|
});
|
|
354
300
|
(0, utils_1.ressert)(res).status.toBe(400);
|
|
355
301
|
})),
|
|
356
|
-
...['string', 0, false, ['array']].map((invalid, index) => (0, utils_1.audit)(`F05${index}`, `SHOULD use 200 status code with errors field on ${(0, utils_1.extendedTypeof)(invalid)} {variables} parameter when accepting application/json`, async () => {
|
|
357
|
-
const res = await fetchFn(await getUrl(opts.url), {
|
|
358
|
-
method: 'POST',
|
|
359
|
-
headers: {
|
|
360
|
-
'content-type': 'application/json',
|
|
361
|
-
accept: 'application/json',
|
|
362
|
-
},
|
|
363
|
-
body: JSON.stringify({
|
|
364
|
-
query: '{ __typename }',
|
|
365
|
-
variables: invalid,
|
|
366
|
-
}),
|
|
367
|
-
});
|
|
368
|
-
(0, utils_1.ressert)(res).status.toBe(200);
|
|
369
|
-
await (0, utils_1.ressert)(res).bodyAsExecutionResult.toHaveProperty('errors');
|
|
370
|
-
})),
|
|
371
302
|
(0, utils_1.audit)(
|
|
372
303
|
// TODO: convert to MUST after watershed
|
|
373
304
|
'2EA1', 'SHOULD allow map {variables} parameter when accepting application/graphql-response+json', async () => {
|
|
@@ -424,14 +355,13 @@ function serverAudits(opts) {
|
|
|
424
355
|
(0, utils_1.ressert)(res).status.toBe(200);
|
|
425
356
|
await (0, utils_1.ressert)(res).bodyAsExecutionResult.notToHaveProperty('errors');
|
|
426
357
|
}),
|
|
427
|
-
...['string', 0, false, ['array']].map((invalid, index) => (0, utils_1.audit)(`
|
|
358
|
+
...['string', 0, false, ['array']].map((invalid, index) => (0, utils_1.audit)(`58B${index}`,
|
|
428
359
|
// TODO: convert to MUST after watershed
|
|
429
|
-
`
|
|
360
|
+
`MAY use 400 status code on ${(0, utils_1.extendedTypeof)(invalid)} {extensions} parameter`, async () => {
|
|
430
361
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
431
362
|
method: 'POST',
|
|
432
363
|
headers: {
|
|
433
364
|
'content-type': 'application/json',
|
|
434
|
-
accept: 'application/graphql-response+json',
|
|
435
365
|
},
|
|
436
366
|
body: JSON.stringify({
|
|
437
367
|
query: '{ __typename }',
|
|
@@ -440,21 +370,6 @@ function serverAudits(opts) {
|
|
|
440
370
|
});
|
|
441
371
|
(0, utils_1.ressert)(res).status.toBe(400);
|
|
442
372
|
})),
|
|
443
|
-
...['string', 0, false, ['array']].map((invalid, index) => (0, utils_1.audit)(`368${index}`, `SHOULD use 200 status code with errors field on ${(0, utils_1.extendedTypeof)(invalid)} {extensions} parameter when accepting application/json`, async () => {
|
|
444
|
-
const res = await fetchFn(await getUrl(opts.url), {
|
|
445
|
-
method: 'POST',
|
|
446
|
-
headers: {
|
|
447
|
-
'content-type': 'application/json',
|
|
448
|
-
accept: 'application/json',
|
|
449
|
-
},
|
|
450
|
-
body: JSON.stringify({
|
|
451
|
-
query: '{ __typename }',
|
|
452
|
-
extensions: invalid,
|
|
453
|
-
}),
|
|
454
|
-
});
|
|
455
|
-
(0, utils_1.ressert)(res).status.toBe(200);
|
|
456
|
-
await (0, utils_1.ressert)(res).bodyAsExecutionResult.toHaveProperty('errors');
|
|
457
|
-
})),
|
|
458
373
|
(0, utils_1.audit)(
|
|
459
374
|
// TODO: convert to MUST after watershed
|
|
460
375
|
'428F', 'SHOULD allow map {extensions} parameter when accepting application/graphql-response+json', async () => {
|
|
@@ -486,136 +401,91 @@ function serverAudits(opts) {
|
|
|
486
401
|
(0, utils_1.ressert)(res).status.toBe(200);
|
|
487
402
|
await (0, utils_1.ressert)(res).bodyAsExecutionResult.notToHaveProperty('errors');
|
|
488
403
|
}),
|
|
489
|
-
|
|
490
|
-
// Response application/json
|
|
491
|
-
(0, utils_1.audit)('D477', 'SHOULD use 200 status code on JSON parsing failure when accepting application/json', async () => {
|
|
404
|
+
(0, utils_1.audit)('B6DC', 'MAY use 4xx or 5xx status codes on JSON parsing failure', async () => {
|
|
492
405
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
493
406
|
method: 'POST',
|
|
494
407
|
headers: {
|
|
495
408
|
'content-type': 'application/json',
|
|
496
|
-
accept: 'application/json',
|
|
497
409
|
},
|
|
498
410
|
body: '{ "not a JSON',
|
|
499
411
|
});
|
|
500
|
-
(0, utils_1.ressert)(res).status.
|
|
501
|
-
}),
|
|
502
|
-
(0, utils_1.audit)('F5AF', 'SHOULD use 200 status code if parameters are invalid when accepting application/json', async () => {
|
|
503
|
-
const res = await fetchFn(await getUrl(opts.url), {
|
|
504
|
-
method: 'POST',
|
|
505
|
-
headers: {
|
|
506
|
-
'content-type': 'application/json',
|
|
507
|
-
accept: 'application/json',
|
|
508
|
-
},
|
|
509
|
-
body: JSON.stringify({
|
|
510
|
-
qeury: /* typo */ '{ __typename }',
|
|
511
|
-
}),
|
|
512
|
-
});
|
|
513
|
-
(0, utils_1.ressert)(res).status.toBe(200);
|
|
412
|
+
(0, utils_1.ressert)(res).status.toBeBetween(400, 499);
|
|
514
413
|
}),
|
|
515
|
-
(0, utils_1.audit)('
|
|
414
|
+
(0, utils_1.audit)('BCF8', 'MAY use 400 status code on JSON parsing failure', async () => {
|
|
516
415
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
517
416
|
method: 'POST',
|
|
518
417
|
headers: {
|
|
519
418
|
'content-type': 'application/json',
|
|
520
|
-
accept: 'application/json',
|
|
521
419
|
},
|
|
522
|
-
body:
|
|
420
|
+
body: '{ "not a JSON',
|
|
523
421
|
});
|
|
524
|
-
(0, utils_1.ressert)(res).status.toBe(
|
|
422
|
+
(0, utils_1.ressert)(res).status.toBe(400);
|
|
525
423
|
}),
|
|
526
|
-
(0, utils_1.audit)('
|
|
424
|
+
(0, utils_1.audit)('8764', 'MAY use 4xx or 5xx status codes if parameters are invalid', async () => {
|
|
527
425
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
528
426
|
method: 'POST',
|
|
529
427
|
headers: {
|
|
530
428
|
'content-type': 'application/json',
|
|
531
|
-
accept: 'application/json',
|
|
532
429
|
},
|
|
533
430
|
body: JSON.stringify({
|
|
534
|
-
|
|
431
|
+
qeury /* typo */: '{ __typename }',
|
|
535
432
|
}),
|
|
536
433
|
});
|
|
537
|
-
(0, utils_1.ressert)(res).status.
|
|
434
|
+
(0, utils_1.ressert)(res).status.toBeBetween(400, 599);
|
|
538
435
|
}),
|
|
539
|
-
(0, utils_1.audit)('
|
|
436
|
+
(0, utils_1.audit)('3E3A', 'MAY use 400 status code if parameters are invalid', async () => {
|
|
540
437
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
541
438
|
method: 'POST',
|
|
542
439
|
headers: {
|
|
543
440
|
'content-type': 'application/json',
|
|
544
|
-
accept: 'application/json',
|
|
545
441
|
},
|
|
546
442
|
body: JSON.stringify({
|
|
547
|
-
|
|
548
|
-
variables: { id: null },
|
|
443
|
+
qeury: /* typo */ '{ __typename }',
|
|
549
444
|
}),
|
|
550
445
|
});
|
|
551
|
-
(0, utils_1.ressert)(res).status.toBe(200);
|
|
552
|
-
}),
|
|
553
|
-
// Response application/graphql-response+json
|
|
554
|
-
(0, utils_1.audit)(
|
|
555
|
-
// TODO: convert to MUST after watershed
|
|
556
|
-
'60AA', 'SHOULD use 4xx or 5xx status codes on JSON parsing failure when accepting application/graphql-response+json', async () => {
|
|
557
|
-
const res = await fetchFn(await getUrl(opts.url), {
|
|
558
|
-
method: 'POST',
|
|
559
|
-
headers: {
|
|
560
|
-
'content-type': 'application/json',
|
|
561
|
-
accept: 'application/graphql-response+json',
|
|
562
|
-
},
|
|
563
|
-
body: '{ "not a JSON',
|
|
564
|
-
});
|
|
565
|
-
(0, utils_1.ressert)(res).status.toBeBetween(400, 499);
|
|
566
|
-
}),
|
|
567
|
-
(0, utils_1.audit)('2163', 'SHOULD use 400 status code on JSON parsing failure when accepting application/graphql-response+json', async () => {
|
|
568
|
-
const res = await fetchFn(await getUrl(opts.url), {
|
|
569
|
-
method: 'POST',
|
|
570
|
-
headers: {
|
|
571
|
-
'content-type': 'application/json',
|
|
572
|
-
accept: 'application/graphql-response+json',
|
|
573
|
-
},
|
|
574
|
-
body: '{ "not a JSON',
|
|
575
|
-
});
|
|
576
446
|
(0, utils_1.ressert)(res).status.toBe(400);
|
|
577
447
|
}),
|
|
578
|
-
(
|
|
579
|
-
//
|
|
580
|
-
'
|
|
448
|
+
// TODO: audit('39AA', 'MUST accept a map for the {extensions} parameter'),
|
|
449
|
+
// Response application/json
|
|
450
|
+
(0, utils_1.audit)('572B', 'SHOULD use 200 status code on document parsing failure when accepting application/json', async () => {
|
|
581
451
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
582
452
|
method: 'POST',
|
|
583
453
|
headers: {
|
|
584
454
|
'content-type': 'application/json',
|
|
585
|
-
accept: 'application/
|
|
455
|
+
accept: 'application/json',
|
|
586
456
|
},
|
|
587
|
-
body: JSON.stringify({
|
|
588
|
-
qeury /* typo */: '{ __typename }',
|
|
589
|
-
}),
|
|
457
|
+
body: JSON.stringify({ query: '{' }),
|
|
590
458
|
});
|
|
591
|
-
(0, utils_1.ressert)(res).status.
|
|
459
|
+
(0, utils_1.ressert)(res).status.toBe(200);
|
|
592
460
|
}),
|
|
593
|
-
(0, utils_1.audit)('
|
|
461
|
+
(0, utils_1.audit)('FDE2', 'SHOULD use 200 status code on document validation failure when accepting application/json', async () => {
|
|
594
462
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
595
463
|
method: 'POST',
|
|
596
464
|
headers: {
|
|
597
465
|
'content-type': 'application/json',
|
|
598
|
-
accept: 'application/
|
|
466
|
+
accept: 'application/json',
|
|
599
467
|
},
|
|
600
468
|
body: JSON.stringify({
|
|
601
|
-
|
|
469
|
+
query: '{ 8f31403dfe404bccbb0e835f2629c6a7 }', // making sure the field doesnt exist
|
|
602
470
|
}),
|
|
603
471
|
});
|
|
604
|
-
(0, utils_1.ressert)(res).status.toBe(
|
|
472
|
+
(0, utils_1.ressert)(res).status.toBe(200);
|
|
605
473
|
}),
|
|
606
|
-
(0, utils_1.audit)('
|
|
474
|
+
(0, utils_1.audit)('7B9B', 'SHOULD use a status code of 200 on variable coercion failure when accepting application/json', async () => {
|
|
607
475
|
const res = await fetchFn(await getUrl(opts.url), {
|
|
608
476
|
method: 'POST',
|
|
609
477
|
headers: {
|
|
610
478
|
'content-type': 'application/json',
|
|
611
|
-
accept: 'application/
|
|
479
|
+
accept: 'application/json',
|
|
612
480
|
},
|
|
613
481
|
body: JSON.stringify({
|
|
614
|
-
|
|
482
|
+
query: 'query CoerceFailure($id: ID!){ __typename }',
|
|
483
|
+
variables: { id: null },
|
|
615
484
|
}),
|
|
616
485
|
});
|
|
617
|
-
|
|
486
|
+
(0, utils_1.ressert)(res).status.toBe(200);
|
|
618
487
|
}),
|
|
488
|
+
// Response application/graphql-response+json
|
|
619
489
|
(0, utils_1.audit)(
|
|
620
490
|
// TODO: convert to MUST after watershed
|
|
621
491
|
'865D', 'SHOULD use 4xx or 5xx status codes on document parsing failure when accepting application/graphql-response+json', async () => {
|