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/LICENSE.md +1 -1
- package/README.md +127 -114
- package/lib/audits/common.d.mts +58 -0
- package/lib/audits/index.d.mts +2 -0
- package/lib/audits/server.d.mts +39 -0
- package/lib/audits/server.js +237 -32
- package/lib/audits/server.mjs +238 -33
- package/lib/audits/utils.d.mts +38 -0
- package/lib/audits/utils.d.ts +11 -0
- package/lib/audits/utils.js +33 -1
- package/lib/audits/utils.mjs +31 -0
- package/lib/client.d.mts +155 -0
- package/lib/common.d.mts +31 -0
- package/lib/handler.d.mts +287 -0
- package/lib/handler.d.ts +26 -24
- package/lib/handler.js +17 -7
- package/lib/handler.mjs +18 -8
- package/lib/index.d.mts +4 -0
- package/lib/index.mjs +1 -1
- 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/lib/utils.d.mts +16 -0
- package/package.json +48 -22
- 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/audits/server.js
CHANGED
|
@@ -16,7 +16,9 @@ function serverAudits(opts) {
|
|
|
16
16
|
const fetchFn = (opts.fetchFn || fetch);
|
|
17
17
|
return [
|
|
18
18
|
// Media Types
|
|
19
|
-
(0, utils_1.audit)(
|
|
19
|
+
(0, utils_1.audit)(
|
|
20
|
+
// TODO: convert to MUST after watershed
|
|
21
|
+
'SHOULD accept application/graphql-response+json and match the content-type', async () => {
|
|
20
22
|
const url = new URL(opts.url);
|
|
21
23
|
url.searchParams.set('query', '{ __typename }');
|
|
22
24
|
const res = await fetchFn(url.toString(), {
|
|
@@ -38,7 +40,9 @@ function serverAudits(opts) {
|
|
|
38
40
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
39
41
|
(0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('application/json');
|
|
40
42
|
}),
|
|
41
|
-
(0, utils_1.audit)(
|
|
43
|
+
(0, utils_1.audit)(
|
|
44
|
+
// TODO: convert to MUST after watershed
|
|
45
|
+
'SHOULD accept */* and use application/graphql-response+json for the content-type', async () => {
|
|
42
46
|
const url = new URL(opts.url);
|
|
43
47
|
url.searchParams.set('query', '{ __typename }');
|
|
44
48
|
const res = await fetchFn(url.toString(), {
|
|
@@ -49,30 +53,61 @@ function serverAudits(opts) {
|
|
|
49
53
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
50
54
|
(0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('application/graphql-response+json');
|
|
51
55
|
}),
|
|
52
|
-
(0, utils_1.audit)(
|
|
56
|
+
(0, utils_1.audit)(
|
|
57
|
+
// TODO: convert to MUST after watershed
|
|
58
|
+
'SHOULD assume application/graphql-response+json content-type when accept is missing', async () => {
|
|
53
59
|
const url = new URL(opts.url);
|
|
54
60
|
url.searchParams.set('query', '{ __typename }');
|
|
55
61
|
const res = await fetchFn(url.toString());
|
|
56
62
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
57
63
|
(0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('application/graphql-response+json');
|
|
58
64
|
}),
|
|
59
|
-
(0, utils_1.audit)('MUST use utf-8
|
|
65
|
+
(0, utils_1.audit)('MUST use utf-8 encoding when responding', async () => {
|
|
60
66
|
const url = new URL(opts.url);
|
|
61
67
|
url.searchParams.set('query', '{ __typename }');
|
|
62
68
|
const res = await fetchFn(url.toString());
|
|
63
69
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
64
|
-
|
|
70
|
+
// has charset set to utf-8
|
|
71
|
+
try {
|
|
72
|
+
(0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('charset=utf-8');
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
catch (_a) {
|
|
76
|
+
// noop, continue
|
|
77
|
+
}
|
|
78
|
+
// has no charset specified
|
|
79
|
+
(0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).notToContain('charset');
|
|
80
|
+
// and the content is utf-8 encoded
|
|
81
|
+
try {
|
|
82
|
+
const decoder = new TextDecoder('utf-8');
|
|
83
|
+
const decoded = decoder.decode(await res.arrayBuffer());
|
|
84
|
+
(0, utils_1.assert)('UTF-8 decoded body', decoded).toBe('{"data":{"__typename":"Query"}}');
|
|
85
|
+
}
|
|
86
|
+
catch (_b) {
|
|
87
|
+
throw 'Body is not UTF-8 encoded';
|
|
88
|
+
}
|
|
89
|
+
}),
|
|
90
|
+
(0, utils_1.audit)('MUST accept utf-8 encoding', async () => {
|
|
91
|
+
const url = new URL(opts.url);
|
|
92
|
+
url.searchParams.set('query', '{ __typename }');
|
|
93
|
+
const res = await fetchFn(url.toString(), {
|
|
94
|
+
headers: {
|
|
95
|
+
'content-type': 'application/json; charset=utf-8',
|
|
96
|
+
},
|
|
97
|
+
});
|
|
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');
|
|
65
100
|
}),
|
|
66
|
-
(0, utils_1.audit)('MUST
|
|
101
|
+
(0, utils_1.audit)('MUST assume utf-8 if encoding is unspecified', async () => {
|
|
67
102
|
const url = new URL(opts.url);
|
|
68
103
|
url.searchParams.set('query', '{ __typename }');
|
|
69
104
|
const res = await fetchFn(url.toString(), {
|
|
70
105
|
headers: {
|
|
71
|
-
|
|
106
|
+
'content-type': 'application/json',
|
|
72
107
|
},
|
|
73
108
|
});
|
|
74
|
-
(0, utils_1.assert)('Status code', res.status).toBe(
|
|
75
|
-
(0, utils_1.assert)('
|
|
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');
|
|
76
111
|
}),
|
|
77
112
|
// Request
|
|
78
113
|
(0, utils_1.audit)('MUST accept POST requests', async () => {
|
|
@@ -106,7 +141,7 @@ function serverAudits(opts) {
|
|
|
106
141
|
method: 'POST',
|
|
107
142
|
});
|
|
108
143
|
(0, utils_1.assert)('Status code', res.status).toBeGreaterThanOrEqual(400);
|
|
109
|
-
(0, utils_1.assert)('Status code', res.status).toBeLessThanOrEqual(
|
|
144
|
+
(0, utils_1.assert)('Status code', res.status).toBeLessThanOrEqual(499);
|
|
110
145
|
}),
|
|
111
146
|
(0, utils_1.audit)('MUST accept application/json POST requests', async () => {
|
|
112
147
|
const res = await fetchFn(opts.url, {
|
|
@@ -124,7 +159,9 @@ function serverAudits(opts) {
|
|
|
124
159
|
(0, utils_1.assert)('Status code', res.status).toBe(400);
|
|
125
160
|
}),
|
|
126
161
|
// Request Parameters
|
|
127
|
-
(0, utils_1.audit)(
|
|
162
|
+
(0, utils_1.audit)(
|
|
163
|
+
// TODO: convert to MUST after watershed
|
|
164
|
+
'SHOULD use 400 status code on missing {query} parameter when accepting application/graphql-response+json', async () => {
|
|
128
165
|
const res = await fetchFn(opts.url, {
|
|
129
166
|
method: 'POST',
|
|
130
167
|
headers: {
|
|
@@ -135,7 +172,21 @@ function serverAudits(opts) {
|
|
|
135
172
|
});
|
|
136
173
|
(0, utils_1.assert)('Status code', res.status).toBe(400);
|
|
137
174
|
}),
|
|
138
|
-
|
|
175
|
+
(0, utils_1.audit)('SHOULD use 200 status code with errors field on missing {query} parameter when accepting application/json', async () => {
|
|
176
|
+
const res = await fetchFn(opts.url, {
|
|
177
|
+
method: 'POST',
|
|
178
|
+
headers: {
|
|
179
|
+
'content-type': 'application/json',
|
|
180
|
+
accept: 'application/json',
|
|
181
|
+
},
|
|
182
|
+
body: JSON.stringify({ notquery: '{ __typename }' }),
|
|
183
|
+
});
|
|
184
|
+
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
185
|
+
(0, utils_1.assert)('Execution result', await (0, utils_1.assertBodyAsExecutionResult)(res)).toHaveProperty('errors');
|
|
186
|
+
}),
|
|
187
|
+
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid) => (0, utils_1.audit)(
|
|
188
|
+
// TODO: convert to MUST after watershed
|
|
189
|
+
`SHOULD use 400 status code on ${(0, utils_1.extendedTypeof)(invalid)} {query} parameter when accepting application/graphql-response+json`, async () => {
|
|
139
190
|
const res = await fetchFn(opts.url, {
|
|
140
191
|
method: 'POST',
|
|
141
192
|
headers: {
|
|
@@ -148,7 +199,23 @@ function serverAudits(opts) {
|
|
|
148
199
|
});
|
|
149
200
|
(0, utils_1.assert)('Status code', res.status).toBe(400);
|
|
150
201
|
})),
|
|
151
|
-
(0, utils_1.audit)(
|
|
202
|
+
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid) => (0, utils_1.audit)(`SHOULD use 200 status code with errors field on ${(0, utils_1.extendedTypeof)(invalid)} {query} parameter when accepting application/json`, async () => {
|
|
203
|
+
const res = await fetchFn(opts.url, {
|
|
204
|
+
method: 'POST',
|
|
205
|
+
headers: {
|
|
206
|
+
'content-type': 'application/json',
|
|
207
|
+
accept: 'application/json',
|
|
208
|
+
},
|
|
209
|
+
body: JSON.stringify({
|
|
210
|
+
query: invalid,
|
|
211
|
+
}),
|
|
212
|
+
});
|
|
213
|
+
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
214
|
+
(0, utils_1.assert)('Execution result', await (0, utils_1.assertBodyAsExecutionResult)(res)).toHaveProperty('errors');
|
|
215
|
+
})),
|
|
216
|
+
(0, utils_1.audit)(
|
|
217
|
+
// TODO: convert to MUST after watershed
|
|
218
|
+
'SHOULD allow string {query} parameter when accepting application/graphql-response+json', async () => {
|
|
152
219
|
const res = await fetchFn(opts.url, {
|
|
153
220
|
method: 'POST',
|
|
154
221
|
headers: {
|
|
@@ -161,7 +228,23 @@ function serverAudits(opts) {
|
|
|
161
228
|
});
|
|
162
229
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
163
230
|
}),
|
|
164
|
-
|
|
231
|
+
(0, utils_1.audit)('MUST allow string {query} parameter when accepting application/json', async () => {
|
|
232
|
+
const res = await fetchFn(opts.url, {
|
|
233
|
+
method: 'POST',
|
|
234
|
+
headers: {
|
|
235
|
+
'content-type': 'application/json',
|
|
236
|
+
accept: 'application/json',
|
|
237
|
+
},
|
|
238
|
+
body: JSON.stringify({
|
|
239
|
+
query: '{ __typename }',
|
|
240
|
+
}),
|
|
241
|
+
});
|
|
242
|
+
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
243
|
+
(0, utils_1.assert)('Execution result', await (0, utils_1.assertBodyAsExecutionResult)(res)).notToHaveProperty('errors');
|
|
244
|
+
}),
|
|
245
|
+
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid) => (0, utils_1.audit)(
|
|
246
|
+
// TODO: convert to MUST after watershed
|
|
247
|
+
`SHOULD use 400 status code on ${(0, utils_1.extendedTypeof)(invalid)} {operationName} parameter when accepting application/graphql-response+json`, async () => {
|
|
165
248
|
const res = await fetchFn(opts.url, {
|
|
166
249
|
method: 'POST',
|
|
167
250
|
headers: {
|
|
@@ -175,7 +258,24 @@ function serverAudits(opts) {
|
|
|
175
258
|
});
|
|
176
259
|
(0, utils_1.assert)('Status code', res.status).toBe(400);
|
|
177
260
|
})),
|
|
178
|
-
(0, utils_1.audit)(
|
|
261
|
+
...[{ obj: 'ect' }, 0, false, ['array']].map((invalid) => (0, utils_1.audit)(`SHOULD use 200 status code with errors field on ${(0, utils_1.extendedTypeof)(invalid)} {operationName} parameter when accepting application/json`, async () => {
|
|
262
|
+
const res = await fetchFn(opts.url, {
|
|
263
|
+
method: 'POST',
|
|
264
|
+
headers: {
|
|
265
|
+
'content-type': 'application/json',
|
|
266
|
+
accept: 'application/json',
|
|
267
|
+
},
|
|
268
|
+
body: JSON.stringify({
|
|
269
|
+
operationName: invalid,
|
|
270
|
+
query: '{ __typename }',
|
|
271
|
+
}),
|
|
272
|
+
});
|
|
273
|
+
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
274
|
+
(0, utils_1.assert)('Execution result', await (0, utils_1.assertBodyAsExecutionResult)(res)).toHaveProperty('errors');
|
|
275
|
+
})),
|
|
276
|
+
(0, utils_1.audit)(
|
|
277
|
+
// TODO: convert to MUST after watershed
|
|
278
|
+
'SHOULD allow string {operationName} parameter when accepting application/graphql-response+json', async () => {
|
|
179
279
|
const res = await fetchFn(opts.url, {
|
|
180
280
|
method: 'POST',
|
|
181
281
|
headers: {
|
|
@@ -189,7 +289,24 @@ function serverAudits(opts) {
|
|
|
189
289
|
});
|
|
190
290
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
191
291
|
}),
|
|
192
|
-
|
|
292
|
+
(0, utils_1.audit)('MUST allow string {operationName} parameter when accepting application/json', async () => {
|
|
293
|
+
const res = await fetchFn(opts.url, {
|
|
294
|
+
method: 'POST',
|
|
295
|
+
headers: {
|
|
296
|
+
'content-type': 'application/json',
|
|
297
|
+
accept: 'application/json',
|
|
298
|
+
},
|
|
299
|
+
body: JSON.stringify({
|
|
300
|
+
operationName: 'Query',
|
|
301
|
+
query: 'query Query { __typename }',
|
|
302
|
+
}),
|
|
303
|
+
});
|
|
304
|
+
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
305
|
+
(0, utils_1.assert)('Execution result', await (0, utils_1.assertBodyAsExecutionResult)(res)).notToHaveProperty('errors');
|
|
306
|
+
}),
|
|
307
|
+
...['string', 0, false, ['array']].map((invalid) => (0, utils_1.audit)(
|
|
308
|
+
// TODO: convert to MUST after watershed
|
|
309
|
+
`SHOULD use 400 status code on ${(0, utils_1.extendedTypeof)(invalid)} {variables} parameter when accepting application/graphql-response+json`, async () => {
|
|
193
310
|
const res = await fetchFn(opts.url, {
|
|
194
311
|
method: 'POST',
|
|
195
312
|
headers: {
|
|
@@ -203,7 +320,24 @@ function serverAudits(opts) {
|
|
|
203
320
|
});
|
|
204
321
|
(0, utils_1.assert)('Status code', res.status).toBe(400);
|
|
205
322
|
})),
|
|
206
|
-
(0, utils_1.audit)(
|
|
323
|
+
...['string', 0, false, ['array']].map((invalid) => (0, utils_1.audit)(`SHOULD use 200 status code with errors field on ${(0, utils_1.extendedTypeof)(invalid)} {variables} parameter when accepting application/json`, async () => {
|
|
324
|
+
const res = await fetchFn(opts.url, {
|
|
325
|
+
method: 'POST',
|
|
326
|
+
headers: {
|
|
327
|
+
'content-type': 'application/json',
|
|
328
|
+
accept: 'application/json',
|
|
329
|
+
},
|
|
330
|
+
body: JSON.stringify({
|
|
331
|
+
query: '{ __typename }',
|
|
332
|
+
variables: invalid,
|
|
333
|
+
}),
|
|
334
|
+
});
|
|
335
|
+
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
336
|
+
(0, utils_1.assert)('Execution result', await (0, utils_1.assertBodyAsExecutionResult)(res)).toHaveProperty('errors');
|
|
337
|
+
})),
|
|
338
|
+
(0, utils_1.audit)(
|
|
339
|
+
// TODO: convert to MUST after watershed
|
|
340
|
+
'SHOULD allow map {variables} parameter when accepting application/graphql-response+json', async () => {
|
|
207
341
|
const res = await fetchFn(opts.url, {
|
|
208
342
|
method: 'POST',
|
|
209
343
|
headers: {
|
|
@@ -216,21 +350,52 @@ function serverAudits(opts) {
|
|
|
216
350
|
}),
|
|
217
351
|
});
|
|
218
352
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
219
|
-
const result = (await res.json());
|
|
220
|
-
(0, utils_1.assert)('Execution result', result).notToHaveProperty('errors');
|
|
221
353
|
}),
|
|
222
|
-
(0, utils_1.audit)('MUST
|
|
354
|
+
(0, utils_1.audit)('MUST allow map {variables} parameter when accepting application/json', async () => {
|
|
355
|
+
const res = await fetchFn(opts.url, {
|
|
356
|
+
method: 'POST',
|
|
357
|
+
headers: {
|
|
358
|
+
'content-type': 'application/json',
|
|
359
|
+
accept: 'application/json',
|
|
360
|
+
},
|
|
361
|
+
body: JSON.stringify({
|
|
362
|
+
query: 'query Type($name: String!) { __type(name: $name) { name } }',
|
|
363
|
+
variables: { name: 'sometype' },
|
|
364
|
+
}),
|
|
365
|
+
});
|
|
366
|
+
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
367
|
+
(0, utils_1.assert)('Execution result', await (0, utils_1.assertBodyAsExecutionResult)(res)).notToHaveProperty('errors');
|
|
368
|
+
}),
|
|
369
|
+
(0, utils_1.audit)(
|
|
370
|
+
// TODO: convert to MUST after watershed
|
|
371
|
+
'SHOULD allow URL-encoded JSON string {variables} parameter in GETs when accepting application/graphql-response+json', async () => {
|
|
372
|
+
const url = new URL(opts.url);
|
|
373
|
+
url.searchParams.set('query', 'query Type($name: String!) { __type(name: $name) { name } }');
|
|
374
|
+
url.searchParams.set('variables', JSON.stringify({ name: 'sometype' }));
|
|
375
|
+
const res = await fetchFn(url.toString(), {
|
|
376
|
+
method: 'GET',
|
|
377
|
+
headers: {
|
|
378
|
+
accept: 'application/graphql-response+json',
|
|
379
|
+
},
|
|
380
|
+
});
|
|
381
|
+
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
382
|
+
}),
|
|
383
|
+
(0, utils_1.audit)('MUST allow URL-encoded JSON string {variables} parameter in GETs when accepting application/json', async () => {
|
|
223
384
|
const url = new URL(opts.url);
|
|
224
385
|
url.searchParams.set('query', 'query Type($name: String!) { __type(name: $name) { name } }');
|
|
225
386
|
url.searchParams.set('variables', JSON.stringify({ name: 'sometype' }));
|
|
226
387
|
const res = await fetchFn(url.toString(), {
|
|
227
388
|
method: 'GET',
|
|
389
|
+
headers: {
|
|
390
|
+
accept: 'application/json',
|
|
391
|
+
},
|
|
228
392
|
});
|
|
229
393
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
230
|
-
|
|
231
|
-
(0, utils_1.assert)('Execution result', result).notToHaveProperty('errors');
|
|
394
|
+
(0, utils_1.assert)('Execution result', await (0, utils_1.assertBodyAsExecutionResult)(res)).notToHaveProperty('errors');
|
|
232
395
|
}),
|
|
233
|
-
...['string', 0, false, ['array']].map((invalid) => (0, utils_1.audit)(
|
|
396
|
+
...['string', 0, false, ['array']].map((invalid) => (0, utils_1.audit)(
|
|
397
|
+
// TODO: convert to MUST after watershed
|
|
398
|
+
`SHOULD use 400 status code on ${(0, utils_1.extendedTypeof)(invalid)} {extensions} parameter when accepting application/graphql-response+json`, async () => {
|
|
234
399
|
const res = await fetchFn(opts.url, {
|
|
235
400
|
method: 'POST',
|
|
236
401
|
headers: {
|
|
@@ -244,7 +409,24 @@ function serverAudits(opts) {
|
|
|
244
409
|
});
|
|
245
410
|
(0, utils_1.assert)('Status code', res.status).toBe(400);
|
|
246
411
|
})),
|
|
247
|
-
(0, utils_1.audit)(
|
|
412
|
+
...['string', 0, false, ['array']].map((invalid) => (0, utils_1.audit)(`SHOULD use 200 status code with errors field on ${(0, utils_1.extendedTypeof)(invalid)} {extensions} parameter when accepting application/json`, async () => {
|
|
413
|
+
const res = await fetchFn(opts.url, {
|
|
414
|
+
method: 'POST',
|
|
415
|
+
headers: {
|
|
416
|
+
'content-type': 'application/json',
|
|
417
|
+
accept: 'application/json',
|
|
418
|
+
},
|
|
419
|
+
body: JSON.stringify({
|
|
420
|
+
query: '{ __typename }',
|
|
421
|
+
extensions: invalid,
|
|
422
|
+
}),
|
|
423
|
+
});
|
|
424
|
+
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
425
|
+
(0, utils_1.assert)('Execution result', await (0, utils_1.assertBodyAsExecutionResult)(res)).toHaveProperty('errors');
|
|
426
|
+
})),
|
|
427
|
+
(0, utils_1.audit)(
|
|
428
|
+
// TODO: convert to MUST after watershed
|
|
429
|
+
'SHOULD allow map {extensions} parameter when accepting application/graphql-response+json', async () => {
|
|
248
430
|
const res = await fetchFn(opts.url, {
|
|
249
431
|
method: 'POST',
|
|
250
432
|
headers: {
|
|
@@ -258,6 +440,21 @@ function serverAudits(opts) {
|
|
|
258
440
|
});
|
|
259
441
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
260
442
|
}),
|
|
443
|
+
(0, utils_1.audit)('MUST allow map {extensions} parameter when accepting application/json', async () => {
|
|
444
|
+
const res = await fetchFn(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: { some: 'value' },
|
|
453
|
+
}),
|
|
454
|
+
});
|
|
455
|
+
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
456
|
+
(0, utils_1.assert)('Execution result', await (0, utils_1.assertBodyAsExecutionResult)(res)).notToHaveProperty('errors');
|
|
457
|
+
}),
|
|
261
458
|
// TODO: audit('MUST accept a map for the {extensions} parameter'),
|
|
262
459
|
// Response application/json
|
|
263
460
|
(0, utils_1.audit)('SHOULD use 200 status code on JSON parsing failure when accepting application/json', async () => {
|
|
@@ -299,7 +496,9 @@ function serverAudits(opts) {
|
|
|
299
496
|
(0, utils_1.assert)('Status code', res.status).toBe(200);
|
|
300
497
|
}),
|
|
301
498
|
// Response application/graphql-response+json
|
|
302
|
-
(0, utils_1.audit)(
|
|
499
|
+
(0, utils_1.audit)(
|
|
500
|
+
// TODO: convert to MUST after watershed
|
|
501
|
+
'SHOULD use 4xx or 5xx status codes on JSON parsing failure when accepting application/graphql-response+json', async () => {
|
|
303
502
|
const res = await fetchFn(opts.url, {
|
|
304
503
|
method: 'POST',
|
|
305
504
|
headers: {
|
|
@@ -331,9 +530,11 @@ function serverAudits(opts) {
|
|
|
331
530
|
},
|
|
332
531
|
body: '{ "not a JSON',
|
|
333
532
|
});
|
|
334
|
-
(0, utils_1.assert)('Data entry', (await
|
|
533
|
+
(0, utils_1.assert)('Data entry', (await (0, utils_1.assertBodyAsExecutionResult)(res)).data).toBe(undefined);
|
|
335
534
|
}),
|
|
336
|
-
(0, utils_1.audit)(
|
|
535
|
+
(0, utils_1.audit)(
|
|
536
|
+
// TODO: convert to MUST after watershed
|
|
537
|
+
'SHOULD use 4xx or 5xx status codes if parameters are invalid when accepting application/graphql-response+json', async () => {
|
|
337
538
|
const url = new URL(opts.url);
|
|
338
539
|
url.searchParams.set('qeury' /* typo */, '{ __typename }');
|
|
339
540
|
const res = await fetchFn(url.toString(), {
|
|
@@ -359,9 +560,11 @@ function serverAudits(opts) {
|
|
|
359
560
|
method: 'GET',
|
|
360
561
|
headers: { accept: 'application/graphql-response+json' },
|
|
361
562
|
});
|
|
362
|
-
(0, utils_1.assert)('Data entry', (await
|
|
563
|
+
(0, utils_1.assert)('Data entry', (await (0, utils_1.assertBodyAsExecutionResult)(res)).data).toBe(undefined);
|
|
363
564
|
}),
|
|
364
|
-
(0, utils_1.audit)(
|
|
565
|
+
(0, utils_1.audit)(
|
|
566
|
+
// TODO: convert to MUST after watershed
|
|
567
|
+
'SHOULD use 4xx or 5xx status codes on document parsing failure when accepting application/graphql-response+json', async () => {
|
|
365
568
|
const url = new URL(opts.url);
|
|
366
569
|
url.searchParams.set('query', '{');
|
|
367
570
|
const res = await fetchFn(url.toString(), {
|
|
@@ -387,9 +590,11 @@ function serverAudits(opts) {
|
|
|
387
590
|
method: 'GET',
|
|
388
591
|
headers: { accept: 'application/graphql-response+json' },
|
|
389
592
|
});
|
|
390
|
-
(0, utils_1.assert)('Data entry', (await
|
|
593
|
+
(0, utils_1.assert)('Data entry', (await (0, utils_1.assertBodyAsExecutionResult)(res)).data).toBe(undefined);
|
|
391
594
|
}),
|
|
392
|
-
(0, utils_1.audit)(
|
|
595
|
+
(0, utils_1.audit)(
|
|
596
|
+
// TODO: convert to MUST after watershed
|
|
597
|
+
'SHOULD use 4xx or 5xx status codes on document validation failure when accepting application/graphql-response+json', async () => {
|
|
393
598
|
const url = new URL(opts.url);
|
|
394
599
|
url.searchParams.set('query', '{ 8f31403dfe404bccbb0e835f2629c6a7 }'); // making sure the field doesnt exist
|
|
395
600
|
const res = await fetchFn(url.toString(), {
|
|
@@ -415,7 +620,7 @@ function serverAudits(opts) {
|
|
|
415
620
|
method: 'GET',
|
|
416
621
|
headers: { accept: 'application/graphql-response+json' },
|
|
417
622
|
});
|
|
418
|
-
(0, utils_1.assert)('Data entry', (await
|
|
623
|
+
(0, utils_1.assert)('Data entry', (await (0, utils_1.assertBodyAsExecutionResult)(res)).data).toBe(undefined);
|
|
419
624
|
}),
|
|
420
625
|
// TODO: how to fail and have the data entry?
|
|
421
626
|
// audit('MUST use 2xx status code if response contains the data entry and it is not null when accepting application/graphql-response+json'),
|