graphql-http 1.7.1 → 1.8.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 CHANGED
@@ -729,13 +729,13 @@ Having said this, graphql-http is mostly aimed for library authors and simple se
729
729
 
730
730
  If you want a feature-full server with bleeding edge technologies, you're recommended to use one of the following.
731
731
 
732
- | Name | Audit |
733
- | ------------------------------------------------------------------ | -------------------------------------------------------------------- |
734
- | [graphql-yoga](https://www.the-guild.dev/graphql/yoga-server) | [✅ Compliant (0 warnings)](/implementations/graphql-yoga/README.md) |
735
- | [hotchocolate](https://chillicream.com/docs/hotchocolate) | [✅ Compliant (0 warnings)](/implementations/hotchocolate/README.md) |
736
- | [postgraphile](https://www.graphile.org/postgraphile/) | [✅ Compliant](/implementations/postgraphile/README.md) |
737
- | [apollo-server](https://www.apollographql.com/docs/apollo-server/) | [✅ Compliant](/implementations/apollo-server/README.md) |
738
- | [mercurius](https://mercurius.dev) | [✅ Compliant](/implementations/mercurius/README.md) |
732
+ | Name | Audit |
733
+ | ------------------------------------------------------------------ | -------------------------------------------------------- |
734
+ | [graphql-yoga](https://www.the-guild.dev/graphql/yoga-server) | [✅ Compliant](/implementations/graphql-yoga/README.md) |
735
+ | [hotchocolate](https://chillicream.com/docs/hotchocolate) | [✅ Compliant](/implementations/hotchocolate/README.md) |
736
+ | [postgraphile](https://www.graphile.org/postgraphile/) | [✅ Compliant](/implementations/postgraphile/README.md) |
737
+ | [apollo-server](https://www.apollographql.com/docs/apollo-server/) | [✅ Compliant](/implementations/apollo-server/README.md) |
738
+ | [mercurius](https://mercurius.dev) | [✅ Compliant](/implementations/mercurius/README.md) |
739
739
 
740
740
  ## [Documentation](docs/)
741
741
 
@@ -12,8 +12,11 @@ import { Audit, AuditResult } from './common';
12
12
  export interface ServerAuditOptions {
13
13
  /**
14
14
  * The URL of the GraphQL server for the audit.
15
+ *
16
+ * A function can be also supplied, in this case -
17
+ * every audit will invoke the function to get the URL.
15
18
  */
16
- url: string;
19
+ url: string | (() => string | Promise<string>);
17
20
  /**
18
21
  * The Fetch function to use.
19
22
  *
@@ -12,8 +12,11 @@ import { Audit, AuditResult } from './common';
12
12
  export interface ServerAuditOptions {
13
13
  /**
14
14
  * The URL of the GraphQL server for the audit.
15
+ *
16
+ * A function can be also supplied, in this case -
17
+ * every audit will invoke the function to get the URL.
15
18
  */
16
- url: string;
19
+ url: string | (() => string | Promise<string>);
17
20
  /**
18
21
  * The Fetch function to use.
19
22
  *
@@ -19,7 +19,7 @@ function serverAudits(opts) {
19
19
  (0, utils_1.audit)(
20
20
  // TODO: convert to MUST after watershed
21
21
  'SHOULD accept application/graphql-response+json and match the content-type', async () => {
22
- const res = await fetchFn(opts.url, {
22
+ const res = await fetchFn(await getUrl(opts.url), {
23
23
  method: 'POST',
24
24
  headers: {
25
25
  'content-type': 'application/json',
@@ -31,7 +31,7 @@ function serverAudits(opts) {
31
31
  (0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('application/graphql-response+json');
32
32
  }),
33
33
  (0, utils_1.audit)('MUST accept application/json and match the content-type', async () => {
34
- const res = await fetchFn(opts.url, {
34
+ const res = await fetchFn(await getUrl(opts.url), {
35
35
  method: 'POST',
36
36
  headers: {
37
37
  'content-type': 'application/json',
@@ -42,10 +42,8 @@ function serverAudits(opts) {
42
42
  (0, utils_1.assert)('Status code', res.status).toBe(200);
43
43
  (0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('application/json');
44
44
  }),
45
- (0, utils_1.audit)(
46
- // TODO: convert to MUST after watershed
47
- 'SHOULD accept */* and use application/graphql-response+json for the content-type', async () => {
48
- const res = await fetchFn(opts.url, {
45
+ (0, utils_1.audit)('SHOULD accept */* and use application/json for the content-type', async () => {
46
+ const res = await fetchFn(await getUrl(opts.url), {
49
47
  method: 'POST',
50
48
  headers: {
51
49
  'content-type': 'application/json',
@@ -54,23 +52,17 @@ function serverAudits(opts) {
54
52
  body: JSON.stringify({ query: '{ __typename }' }),
55
53
  });
56
54
  (0, utils_1.assert)('Status code', res.status).toBe(200);
57
- (0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('application/graphql-response+json');
55
+ (0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('application/json');
58
56
  }),
59
- (0, utils_1.audit)(
60
- // TODO: convert to MUST after watershed
61
- 'SHOULD assume application/graphql-response+json content-type when accept is missing', async () => {
62
- const res = await fetchFn(opts.url, {
63
- method: 'POST',
64
- headers: {
65
- 'content-type': 'application/json',
66
- },
67
- body: JSON.stringify({ query: '{ __typename }' }),
68
- });
57
+ (0, utils_1.audit)('SHOULD assume application/json content-type when accept is missing', async () => {
58
+ const url = new URL(await getUrl(opts.url));
59
+ url.searchParams.set('query', '{ __typename }');
60
+ const res = await fetchFn(url.toString());
69
61
  (0, utils_1.assert)('Status code', res.status).toBe(200);
70
- (0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('application/graphql-response+json');
62
+ (0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('application/json');
71
63
  }),
72
64
  (0, utils_1.audit)('MUST use utf-8 encoding when responding', async () => {
73
- const res = await fetchFn(opts.url, {
65
+ const res = await fetchFn(await getUrl(opts.url), {
74
66
  method: 'POST',
75
67
  headers: {
76
68
  'content-type': 'application/json',
@@ -99,7 +91,7 @@ function serverAudits(opts) {
99
91
  }
100
92
  }),
101
93
  (0, utils_1.audit)('MUST accept utf-8 encoding', async () => {
102
- const res = await fetchFn(opts.url, {
94
+ const res = await fetchFn(await getUrl(opts.url), {
103
95
  method: 'POST',
104
96
  headers: {
105
97
  'content-type': 'application/json; charset=utf-8',
@@ -110,7 +102,7 @@ function serverAudits(opts) {
110
102
  (0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('utf-8');
111
103
  }),
112
104
  (0, utils_1.audit)('MUST assume utf-8 if encoding is unspecified', async () => {
113
- const res = await fetchFn(opts.url, {
105
+ const res = await fetchFn(await getUrl(opts.url), {
114
106
  method: 'POST',
115
107
  headers: {
116
108
  'content-type': 'application/json',
@@ -122,7 +114,7 @@ function serverAudits(opts) {
122
114
  }),
123
115
  // Request
124
116
  (0, utils_1.audit)('MUST accept POST requests', async () => {
125
- const res = await fetchFn(opts.url, {
117
+ const res = await fetchFn(await getUrl(opts.url), {
126
118
  method: 'POST',
127
119
  headers: { 'content-type': 'application/json' },
128
120
  body: JSON.stringify({ query: '{ __typename }' }),
@@ -130,7 +122,7 @@ function serverAudits(opts) {
130
122
  (0, utils_1.assert)('Status code', res.status).toBe(200);
131
123
  }),
132
124
  (0, utils_1.audit)('MAY accept application/x-www-form-urlencoded formatted GET requests', async () => {
133
- const url = new URL(opts.url);
125
+ const url = new URL(await getUrl(opts.url));
134
126
  url.searchParams.set('query', '{ __typename }');
135
127
  const res = await fetchFn(url.toString());
136
128
  (0, utils_1.assert)('Status code', res.status).toBe(200);
@@ -138,7 +130,7 @@ function serverAudits(opts) {
138
130
  // Request GET
139
131
  // TODO: this is a MUST if the server supports GET requests
140
132
  (0, utils_1.audit)('MAY NOT allow executing mutations on GET requests', async () => {
141
- const url = new URL(opts.url);
133
+ const url = new URL(await getUrl(opts.url));
142
134
  url.searchParams.set('query', 'mutation { __typename }');
143
135
  const res = await fetchFn(url.toString(), {
144
136
  headers: {
@@ -149,13 +141,13 @@ function serverAudits(opts) {
149
141
  }),
150
142
  // Request POST
151
143
  (0, utils_1.audit)('SHOULD respond with 4xx status code if content-type is not supplied on POST requests', async () => {
152
- const res = await fetchFn(opts.url, {
144
+ const res = await fetchFn(await getUrl(opts.url), {
153
145
  method: 'POST',
154
146
  });
155
147
  (0, utils_1.assert)('Status code', res.status).toBeBetween(400, 499);
156
148
  }),
157
149
  (0, utils_1.audit)('MUST accept application/json POST requests', async () => {
158
- const res = await fetchFn(opts.url, {
150
+ const res = await fetchFn(await getUrl(opts.url), {
159
151
  method: 'POST',
160
152
  headers: { 'content-type': 'application/json' },
161
153
  body: JSON.stringify({ query: '{ __typename }' }),
@@ -163,17 +155,23 @@ function serverAudits(opts) {
163
155
  (0, utils_1.assert)('Status code', res.status).toBe(200);
164
156
  }),
165
157
  (0, utils_1.audit)('MUST require a request body on POST', async () => {
166
- const res = await fetchFn(opts.url, {
158
+ var _a;
159
+ const res = await fetchFn(await getUrl(opts.url), {
167
160
  method: 'POST',
168
161
  headers: { 'content-type': 'application/json' },
169
162
  });
170
- (0, utils_1.assert)('Status code', res.status).toBe(400);
163
+ if ((_a = res.headers.get('content-type')) === null || _a === void 0 ? void 0 : _a.includes('application/json')) {
164
+ (0, utils_1.assert)('Execution result', await (0, utils_1.assertBodyAsExecutionResult)(res)).toHaveProperty('errors');
165
+ }
166
+ else {
167
+ (0, utils_1.assert)('Status code', res.status).toBe(400);
168
+ }
171
169
  }),
172
170
  // Request Parameters
173
171
  (0, utils_1.audit)(
174
172
  // TODO: convert to MUST after watershed
175
173
  'SHOULD use 400 status code on missing {query} parameter when accepting application/graphql-response+json', async () => {
176
- const res = await fetchFn(opts.url, {
174
+ const res = await fetchFn(await getUrl(opts.url), {
177
175
  method: 'POST',
178
176
  headers: {
179
177
  'content-type': 'application/json',
@@ -184,7 +182,7 @@ function serverAudits(opts) {
184
182
  (0, utils_1.assert)('Status code', res.status).toBe(400);
185
183
  }),
186
184
  (0, utils_1.audit)('SHOULD use 200 status code with errors field on missing {query} parameter when accepting application/json', async () => {
187
- const res = await fetchFn(opts.url, {
185
+ const res = await fetchFn(await getUrl(opts.url), {
188
186
  method: 'POST',
189
187
  headers: {
190
188
  'content-type': 'application/json',
@@ -198,7 +196,7 @@ function serverAudits(opts) {
198
196
  ...[{ obj: 'ect' }, 0, false, ['array']].map((invalid) => (0, utils_1.audit)(
199
197
  // TODO: convert to MUST after watershed
200
198
  `SHOULD use 400 status code on ${(0, utils_1.extendedTypeof)(invalid)} {query} parameter when accepting application/graphql-response+json`, async () => {
201
- const res = await fetchFn(opts.url, {
199
+ const res = await fetchFn(await getUrl(opts.url), {
202
200
  method: 'POST',
203
201
  headers: {
204
202
  'content-type': 'application/json',
@@ -211,7 +209,7 @@ function serverAudits(opts) {
211
209
  (0, utils_1.assert)('Status code', res.status).toBe(400);
212
210
  })),
213
211
  ...[{ 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 () => {
214
- const res = await fetchFn(opts.url, {
212
+ const res = await fetchFn(await getUrl(opts.url), {
215
213
  method: 'POST',
216
214
  headers: {
217
215
  'content-type': 'application/json',
@@ -227,7 +225,7 @@ function serverAudits(opts) {
227
225
  (0, utils_1.audit)(
228
226
  // TODO: convert to MUST after watershed
229
227
  'SHOULD allow string {query} parameter when accepting application/graphql-response+json', async () => {
230
- const res = await fetchFn(opts.url, {
228
+ const res = await fetchFn(await getUrl(opts.url), {
231
229
  method: 'POST',
232
230
  headers: {
233
231
  'content-type': 'application/json',
@@ -240,7 +238,7 @@ function serverAudits(opts) {
240
238
  (0, utils_1.assert)('Status code', res.status).toBe(200);
241
239
  }),
242
240
  (0, utils_1.audit)('MUST allow string {query} parameter when accepting application/json', async () => {
243
- const res = await fetchFn(opts.url, {
241
+ const res = await fetchFn(await getUrl(opts.url), {
244
242
  method: 'POST',
245
243
  headers: {
246
244
  'content-type': 'application/json',
@@ -256,7 +254,7 @@ function serverAudits(opts) {
256
254
  ...[{ obj: 'ect' }, 0, false, ['array']].map((invalid) => (0, utils_1.audit)(
257
255
  // TODO: convert to MUST after watershed
258
256
  `SHOULD use 400 status code on ${(0, utils_1.extendedTypeof)(invalid)} {operationName} parameter when accepting application/graphql-response+json`, async () => {
259
- const res = await fetchFn(opts.url, {
257
+ const res = await fetchFn(await getUrl(opts.url), {
260
258
  method: 'POST',
261
259
  headers: {
262
260
  'content-type': 'application/json',
@@ -270,7 +268,7 @@ function serverAudits(opts) {
270
268
  (0, utils_1.assert)('Status code', res.status).toBe(400);
271
269
  })),
272
270
  ...[{ 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 () => {
273
- const res = await fetchFn(opts.url, {
271
+ const res = await fetchFn(await getUrl(opts.url), {
274
272
  method: 'POST',
275
273
  headers: {
276
274
  'content-type': 'application/json',
@@ -287,7 +285,7 @@ function serverAudits(opts) {
287
285
  (0, utils_1.audit)(
288
286
  // TODO: convert to MUST after watershed
289
287
  'SHOULD allow string {operationName} parameter when accepting application/graphql-response+json', async () => {
290
- const res = await fetchFn(opts.url, {
288
+ const res = await fetchFn(await getUrl(opts.url), {
291
289
  method: 'POST',
292
290
  headers: {
293
291
  'content-type': 'application/json',
@@ -301,7 +299,7 @@ function serverAudits(opts) {
301
299
  (0, utils_1.assert)('Status code', res.status).toBe(200);
302
300
  }),
303
301
  (0, utils_1.audit)('MUST allow string {operationName} parameter when accepting application/json', async () => {
304
- const res = await fetchFn(opts.url, {
302
+ const res = await fetchFn(await getUrl(opts.url), {
305
303
  method: 'POST',
306
304
  headers: {
307
305
  'content-type': 'application/json',
@@ -318,7 +316,7 @@ function serverAudits(opts) {
318
316
  ...['string', 0, false, ['array']].map((invalid) => (0, utils_1.audit)(
319
317
  // TODO: convert to MUST after watershed
320
318
  `SHOULD use 400 status code on ${(0, utils_1.extendedTypeof)(invalid)} {variables} parameter when accepting application/graphql-response+json`, async () => {
321
- const res = await fetchFn(opts.url, {
319
+ const res = await fetchFn(await getUrl(opts.url), {
322
320
  method: 'POST',
323
321
  headers: {
324
322
  'content-type': 'application/json',
@@ -332,7 +330,7 @@ function serverAudits(opts) {
332
330
  (0, utils_1.assert)('Status code', res.status).toBe(400);
333
331
  })),
334
332
  ...['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 () => {
335
- const res = await fetchFn(opts.url, {
333
+ const res = await fetchFn(await getUrl(opts.url), {
336
334
  method: 'POST',
337
335
  headers: {
338
336
  'content-type': 'application/json',
@@ -349,7 +347,7 @@ function serverAudits(opts) {
349
347
  (0, utils_1.audit)(
350
348
  // TODO: convert to MUST after watershed
351
349
  'SHOULD allow map {variables} parameter when accepting application/graphql-response+json', async () => {
352
- const res = await fetchFn(opts.url, {
350
+ const res = await fetchFn(await getUrl(opts.url), {
353
351
  method: 'POST',
354
352
  headers: {
355
353
  'content-type': 'application/json',
@@ -363,7 +361,7 @@ function serverAudits(opts) {
363
361
  (0, utils_1.assert)('Status code', res.status).toBe(200);
364
362
  }),
365
363
  (0, utils_1.audit)('MUST allow map {variables} parameter when accepting application/json', async () => {
366
- const res = await fetchFn(opts.url, {
364
+ const res = await fetchFn(await getUrl(opts.url), {
367
365
  method: 'POST',
368
366
  headers: {
369
367
  'content-type': 'application/json',
@@ -378,7 +376,7 @@ function serverAudits(opts) {
378
376
  (0, utils_1.assert)('Execution result', await (0, utils_1.assertBodyAsExecutionResult)(res)).notToHaveProperty('errors');
379
377
  }),
380
378
  (0, utils_1.audit)('MAY allow URL-encoded JSON string {variables} parameter in GETs when accepting application/graphql-response+json', async () => {
381
- const url = new URL(opts.url);
379
+ const url = new URL(await getUrl(opts.url));
382
380
  url.searchParams.set('query', 'query Type($name: String!) { __type(name: $name) { name } }');
383
381
  url.searchParams.set('variables', JSON.stringify({ name: 'sometype' }));
384
382
  const res = await fetchFn(url.toString(), {
@@ -390,7 +388,7 @@ function serverAudits(opts) {
390
388
  (0, utils_1.assert)('Status code', res.status).toBe(200);
391
389
  }),
392
390
  (0, utils_1.audit)('MAY allow URL-encoded JSON string {variables} parameter in GETs when accepting application/json', async () => {
393
- const url = new URL(opts.url);
391
+ const url = new URL(await getUrl(opts.url));
394
392
  url.searchParams.set('query', 'query Type($name: String!) { __type(name: $name) { name } }');
395
393
  url.searchParams.set('variables', JSON.stringify({ name: 'sometype' }));
396
394
  const res = await fetchFn(url.toString(), {
@@ -405,7 +403,7 @@ function serverAudits(opts) {
405
403
  ...['string', 0, false, ['array']].map((invalid) => (0, utils_1.audit)(
406
404
  // TODO: convert to MUST after watershed
407
405
  `SHOULD use 400 status code on ${(0, utils_1.extendedTypeof)(invalid)} {extensions} parameter when accepting application/graphql-response+json`, async () => {
408
- const res = await fetchFn(opts.url, {
406
+ const res = await fetchFn(await getUrl(opts.url), {
409
407
  method: 'POST',
410
408
  headers: {
411
409
  'content-type': 'application/json',
@@ -419,7 +417,7 @@ function serverAudits(opts) {
419
417
  (0, utils_1.assert)('Status code', res.status).toBe(400);
420
418
  })),
421
419
  ...['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 () => {
422
- const res = await fetchFn(opts.url, {
420
+ const res = await fetchFn(await getUrl(opts.url), {
423
421
  method: 'POST',
424
422
  headers: {
425
423
  'content-type': 'application/json',
@@ -436,7 +434,7 @@ function serverAudits(opts) {
436
434
  (0, utils_1.audit)(
437
435
  // TODO: convert to MUST after watershed
438
436
  'SHOULD allow map {extensions} parameter when accepting application/graphql-response+json', async () => {
439
- const res = await fetchFn(opts.url, {
437
+ const res = await fetchFn(await getUrl(opts.url), {
440
438
  method: 'POST',
441
439
  headers: {
442
440
  'content-type': 'application/json',
@@ -450,7 +448,7 @@ function serverAudits(opts) {
450
448
  (0, utils_1.assert)('Status code', res.status).toBe(200);
451
449
  }),
452
450
  (0, utils_1.audit)('MUST allow map {extensions} parameter when accepting application/json', async () => {
453
- const res = await fetchFn(opts.url, {
451
+ const res = await fetchFn(await getUrl(opts.url), {
454
452
  method: 'POST',
455
453
  headers: {
456
454
  'content-type': 'application/json',
@@ -467,7 +465,7 @@ function serverAudits(opts) {
467
465
  // TODO: audit('MUST accept a map for the {extensions} parameter'),
468
466
  // Response application/json
469
467
  (0, utils_1.audit)('SHOULD use 200 status code on JSON parsing failure when accepting application/json', async () => {
470
- const res = await fetchFn(opts.url, {
468
+ const res = await fetchFn(await getUrl(opts.url), {
471
469
  method: 'POST',
472
470
  headers: {
473
471
  'content-type': 'application/json',
@@ -478,7 +476,7 @@ function serverAudits(opts) {
478
476
  (0, utils_1.assert)('Status code', res.status).toBe(200);
479
477
  }),
480
478
  (0, utils_1.audit)('SHOULD use 200 status code if parameters are invalid when accepting application/json', async () => {
481
- const res = await fetchFn(opts.url, {
479
+ const res = await fetchFn(await getUrl(opts.url), {
482
480
  method: 'POST',
483
481
  headers: {
484
482
  'content-type': 'application/json',
@@ -491,7 +489,7 @@ function serverAudits(opts) {
491
489
  (0, utils_1.assert)('Status code', res.status).toBe(200);
492
490
  }),
493
491
  (0, utils_1.audit)('SHOULD use 200 status code on document parsing failure when accepting application/json', async () => {
494
- const res = await fetchFn(opts.url, {
492
+ const res = await fetchFn(await getUrl(opts.url), {
495
493
  method: 'POST',
496
494
  headers: {
497
495
  'content-type': 'application/json',
@@ -502,7 +500,7 @@ function serverAudits(opts) {
502
500
  (0, utils_1.assert)('Status code', res.status).toBe(200);
503
501
  }),
504
502
  (0, utils_1.audit)('SHOULD use 200 status code on document validation failure when accepting application/json', async () => {
505
- const res = await fetchFn(opts.url, {
503
+ const res = await fetchFn(await getUrl(opts.url), {
506
504
  method: 'POST',
507
505
  headers: {
508
506
  'content-type': 'application/json',
@@ -518,7 +516,7 @@ function serverAudits(opts) {
518
516
  (0, utils_1.audit)(
519
517
  // TODO: convert to MUST after watershed
520
518
  'SHOULD use 4xx or 5xx status codes on JSON parsing failure when accepting application/graphql-response+json', async () => {
521
- const res = await fetchFn(opts.url, {
519
+ const res = await fetchFn(await getUrl(opts.url), {
522
520
  method: 'POST',
523
521
  headers: {
524
522
  'content-type': 'application/json',
@@ -529,7 +527,7 @@ function serverAudits(opts) {
529
527
  (0, utils_1.assert)('Status code', res.status).toBeBetween(400, 499);
530
528
  }),
531
529
  (0, utils_1.audit)('SHOULD use 400 status code on JSON parsing failure when accepting application/graphql-response+json', async () => {
532
- const res = await fetchFn(opts.url, {
530
+ const res = await fetchFn(await getUrl(opts.url), {
533
531
  method: 'POST',
534
532
  headers: {
535
533
  'content-type': 'application/json',
@@ -540,7 +538,7 @@ function serverAudits(opts) {
540
538
  (0, utils_1.assert)('Status code', res.status).toBe(400);
541
539
  }),
542
540
  (0, utils_1.audit)('SHOULD not contain the data entry on JSON parsing failure when accepting application/graphql-response+json', async () => {
543
- const res = await fetchFn(opts.url, {
541
+ const res = await fetchFn(await getUrl(opts.url), {
544
542
  method: 'POST',
545
543
  headers: {
546
544
  'content-type': 'application/json',
@@ -553,7 +551,7 @@ function serverAudits(opts) {
553
551
  (0, utils_1.audit)(
554
552
  // TODO: convert to MUST after watershed
555
553
  'SHOULD use 4xx or 5xx status codes if parameters are invalid when accepting application/graphql-response+json', async () => {
556
- const res = await fetchFn(opts.url, {
554
+ const res = await fetchFn(await getUrl(opts.url), {
557
555
  method: 'POST',
558
556
  headers: {
559
557
  'content-type': 'application/json',
@@ -566,7 +564,7 @@ function serverAudits(opts) {
566
564
  (0, utils_1.assert)('Status code', res.status).toBeBetween(400, 599);
567
565
  }),
568
566
  (0, utils_1.audit)('SHOULD use 400 status code if parameters are invalid when accepting application/graphql-response+json', async () => {
569
- const res = await fetchFn(opts.url, {
567
+ const res = await fetchFn(await getUrl(opts.url), {
570
568
  method: 'POST',
571
569
  headers: {
572
570
  'content-type': 'application/json',
@@ -579,7 +577,7 @@ function serverAudits(opts) {
579
577
  (0, utils_1.assert)('Status code', res.status).toBe(400);
580
578
  }),
581
579
  (0, utils_1.audit)('SHOULD not contain the data entry if parameters are invalid when accepting application/graphql-response+json', async () => {
582
- const res = await fetchFn(opts.url, {
580
+ const res = await fetchFn(await getUrl(opts.url), {
583
581
  method: 'POST',
584
582
  headers: {
585
583
  'content-type': 'application/json',
@@ -594,7 +592,7 @@ function serverAudits(opts) {
594
592
  (0, utils_1.audit)(
595
593
  // TODO: convert to MUST after watershed
596
594
  'SHOULD use 4xx or 5xx status codes on document parsing failure when accepting application/graphql-response+json', async () => {
597
- const res = await fetchFn(opts.url, {
595
+ const res = await fetchFn(await getUrl(opts.url), {
598
596
  method: 'POST',
599
597
  headers: {
600
598
  'content-type': 'application/json',
@@ -607,7 +605,7 @@ function serverAudits(opts) {
607
605
  (0, utils_1.assert)('Status code', res.status).toBeBetween(400, 599);
608
606
  }),
609
607
  (0, utils_1.audit)('SHOULD use 400 status code on document parsing failure when accepting application/graphql-response+json', async () => {
610
- const res = await fetchFn(opts.url, {
608
+ const res = await fetchFn(await getUrl(opts.url), {
611
609
  method: 'POST',
612
610
  headers: {
613
611
  'content-type': 'application/json',
@@ -620,7 +618,7 @@ function serverAudits(opts) {
620
618
  (0, utils_1.assert)('Status code', res.status).toBe(400);
621
619
  }),
622
620
  (0, utils_1.audit)('SHOULD not contain the data entry on document parsing failure when accepting application/graphql-response+json', async () => {
623
- const res = await fetchFn(opts.url, {
621
+ const res = await fetchFn(await getUrl(opts.url), {
624
622
  method: 'POST',
625
623
  headers: {
626
624
  'content-type': 'application/json',
@@ -635,7 +633,7 @@ function serverAudits(opts) {
635
633
  (0, utils_1.audit)(
636
634
  // TODO: convert to MUST after watershed
637
635
  'SHOULD use 4xx or 5xx status codes on document validation failure when accepting application/graphql-response+json', async () => {
638
- const res = await fetchFn(opts.url, {
636
+ const res = await fetchFn(await getUrl(opts.url), {
639
637
  method: 'POST',
640
638
  headers: {
641
639
  'content-type': 'application/json',
@@ -648,7 +646,7 @@ function serverAudits(opts) {
648
646
  (0, utils_1.assert)('Status code', res.status).toBeBetween(400, 599);
649
647
  }),
650
648
  (0, utils_1.audit)('SHOULD use 400 status code on document validation failure when accepting application/graphql-response+json', async () => {
651
- const res = await fetchFn(opts.url, {
649
+ const res = await fetchFn(await getUrl(opts.url), {
652
650
  method: 'POST',
653
651
  headers: {
654
652
  'content-type': 'application/json',
@@ -661,7 +659,7 @@ function serverAudits(opts) {
661
659
  (0, utils_1.assert)('Status code', res.status).toBe(400);
662
660
  }),
663
661
  (0, utils_1.audit)('SHOULD not contain the data entry on document validation failure when accepting application/graphql-response+json', async () => {
664
- const res = await fetchFn(opts.url, {
662
+ const res = await fetchFn(await getUrl(opts.url), {
665
663
  method: 'POST',
666
664
  headers: {
667
665
  'content-type': 'application/json',
@@ -694,3 +692,10 @@ async function auditServer(opts) {
694
692
  return await Promise.all(audits.map(({ fn }) => fn()));
695
693
  }
696
694
  exports.auditServer = auditServer;
695
+ /** @private */
696
+ async function getUrl(url) {
697
+ if (typeof url === 'string') {
698
+ return url;
699
+ }
700
+ return await url();
701
+ }
@@ -16,7 +16,7 @@ export function serverAudits(opts) {
16
16
  audit(
17
17
  // TODO: convert to MUST after watershed
18
18
  'SHOULD accept application/graphql-response+json and match the content-type', async () => {
19
- const res = await fetchFn(opts.url, {
19
+ const res = await fetchFn(await getUrl(opts.url), {
20
20
  method: 'POST',
21
21
  headers: {
22
22
  'content-type': 'application/json',
@@ -28,7 +28,7 @@ export function serverAudits(opts) {
28
28
  assert('Content-Type header', res.headers.get('content-type')).toContain('application/graphql-response+json');
29
29
  }),
30
30
  audit('MUST accept application/json and match the content-type', async () => {
31
- const res = await fetchFn(opts.url, {
31
+ const res = await fetchFn(await getUrl(opts.url), {
32
32
  method: 'POST',
33
33
  headers: {
34
34
  'content-type': 'application/json',
@@ -39,10 +39,8 @@ export function serverAudits(opts) {
39
39
  assert('Status code', res.status).toBe(200);
40
40
  assert('Content-Type header', res.headers.get('content-type')).toContain('application/json');
41
41
  }),
42
- audit(
43
- // TODO: convert to MUST after watershed
44
- 'SHOULD accept */* and use application/graphql-response+json for the content-type', async () => {
45
- const res = await fetchFn(opts.url, {
42
+ audit('SHOULD accept */* and use application/json for the content-type', async () => {
43
+ const res = await fetchFn(await getUrl(opts.url), {
46
44
  method: 'POST',
47
45
  headers: {
48
46
  'content-type': 'application/json',
@@ -51,23 +49,17 @@ export function serverAudits(opts) {
51
49
  body: JSON.stringify({ query: '{ __typename }' }),
52
50
  });
53
51
  assert('Status code', res.status).toBe(200);
54
- assert('Content-Type header', res.headers.get('content-type')).toContain('application/graphql-response+json');
52
+ assert('Content-Type header', res.headers.get('content-type')).toContain('application/json');
55
53
  }),
56
- audit(
57
- // TODO: convert to MUST after watershed
58
- 'SHOULD assume application/graphql-response+json content-type when accept is missing', async () => {
59
- const res = await fetchFn(opts.url, {
60
- method: 'POST',
61
- headers: {
62
- 'content-type': 'application/json',
63
- },
64
- body: JSON.stringify({ query: '{ __typename }' }),
65
- });
54
+ audit('SHOULD assume application/json content-type when accept is missing', async () => {
55
+ const url = new URL(await getUrl(opts.url));
56
+ url.searchParams.set('query', '{ __typename }');
57
+ const res = await fetchFn(url.toString());
66
58
  assert('Status code', res.status).toBe(200);
67
- assert('Content-Type header', res.headers.get('content-type')).toContain('application/graphql-response+json');
59
+ assert('Content-Type header', res.headers.get('content-type')).toContain('application/json');
68
60
  }),
69
61
  audit('MUST use utf-8 encoding when responding', async () => {
70
- const res = await fetchFn(opts.url, {
62
+ const res = await fetchFn(await getUrl(opts.url), {
71
63
  method: 'POST',
72
64
  headers: {
73
65
  'content-type': 'application/json',
@@ -96,7 +88,7 @@ export function serverAudits(opts) {
96
88
  }
97
89
  }),
98
90
  audit('MUST accept utf-8 encoding', async () => {
99
- const res = await fetchFn(opts.url, {
91
+ const res = await fetchFn(await getUrl(opts.url), {
100
92
  method: 'POST',
101
93
  headers: {
102
94
  'content-type': 'application/json; charset=utf-8',
@@ -107,7 +99,7 @@ export function serverAudits(opts) {
107
99
  assert('Content-Type header', res.headers.get('content-type')).toContain('utf-8');
108
100
  }),
109
101
  audit('MUST assume utf-8 if encoding is unspecified', async () => {
110
- const res = await fetchFn(opts.url, {
102
+ const res = await fetchFn(await getUrl(opts.url), {
111
103
  method: 'POST',
112
104
  headers: {
113
105
  'content-type': 'application/json',
@@ -119,7 +111,7 @@ export function serverAudits(opts) {
119
111
  }),
120
112
  // Request
121
113
  audit('MUST accept POST requests', async () => {
122
- const res = await fetchFn(opts.url, {
114
+ const res = await fetchFn(await getUrl(opts.url), {
123
115
  method: 'POST',
124
116
  headers: { 'content-type': 'application/json' },
125
117
  body: JSON.stringify({ query: '{ __typename }' }),
@@ -127,7 +119,7 @@ export function serverAudits(opts) {
127
119
  assert('Status code', res.status).toBe(200);
128
120
  }),
129
121
  audit('MAY accept application/x-www-form-urlencoded formatted GET requests', async () => {
130
- const url = new URL(opts.url);
122
+ const url = new URL(await getUrl(opts.url));
131
123
  url.searchParams.set('query', '{ __typename }');
132
124
  const res = await fetchFn(url.toString());
133
125
  assert('Status code', res.status).toBe(200);
@@ -135,7 +127,7 @@ export function serverAudits(opts) {
135
127
  // Request GET
136
128
  // TODO: this is a MUST if the server supports GET requests
137
129
  audit('MAY NOT allow executing mutations on GET requests', async () => {
138
- const url = new URL(opts.url);
130
+ const url = new URL(await getUrl(opts.url));
139
131
  url.searchParams.set('query', 'mutation { __typename }');
140
132
  const res = await fetchFn(url.toString(), {
141
133
  headers: {
@@ -146,13 +138,13 @@ export function serverAudits(opts) {
146
138
  }),
147
139
  // Request POST
148
140
  audit('SHOULD respond with 4xx status code if content-type is not supplied on POST requests', async () => {
149
- const res = await fetchFn(opts.url, {
141
+ const res = await fetchFn(await getUrl(opts.url), {
150
142
  method: 'POST',
151
143
  });
152
144
  assert('Status code', res.status).toBeBetween(400, 499);
153
145
  }),
154
146
  audit('MUST accept application/json POST requests', async () => {
155
- const res = await fetchFn(opts.url, {
147
+ const res = await fetchFn(await getUrl(opts.url), {
156
148
  method: 'POST',
157
149
  headers: { 'content-type': 'application/json' },
158
150
  body: JSON.stringify({ query: '{ __typename }' }),
@@ -160,17 +152,23 @@ export function serverAudits(opts) {
160
152
  assert('Status code', res.status).toBe(200);
161
153
  }),
162
154
  audit('MUST require a request body on POST', async () => {
163
- const res = await fetchFn(opts.url, {
155
+ var _a;
156
+ const res = await fetchFn(await getUrl(opts.url), {
164
157
  method: 'POST',
165
158
  headers: { 'content-type': 'application/json' },
166
159
  });
167
- assert('Status code', res.status).toBe(400);
160
+ if ((_a = res.headers.get('content-type')) === null || _a === void 0 ? void 0 : _a.includes('application/json')) {
161
+ assert('Execution result', await assertBodyAsExecutionResult(res)).toHaveProperty('errors');
162
+ }
163
+ else {
164
+ assert('Status code', res.status).toBe(400);
165
+ }
168
166
  }),
169
167
  // Request Parameters
170
168
  audit(
171
169
  // TODO: convert to MUST after watershed
172
170
  'SHOULD use 400 status code on missing {query} parameter when accepting application/graphql-response+json', async () => {
173
- const res = await fetchFn(opts.url, {
171
+ const res = await fetchFn(await getUrl(opts.url), {
174
172
  method: 'POST',
175
173
  headers: {
176
174
  'content-type': 'application/json',
@@ -181,7 +179,7 @@ export function serverAudits(opts) {
181
179
  assert('Status code', res.status).toBe(400);
182
180
  }),
183
181
  audit('SHOULD use 200 status code with errors field on missing {query} parameter when accepting application/json', async () => {
184
- const res = await fetchFn(opts.url, {
182
+ const res = await fetchFn(await getUrl(opts.url), {
185
183
  method: 'POST',
186
184
  headers: {
187
185
  'content-type': 'application/json',
@@ -195,7 +193,7 @@ export function serverAudits(opts) {
195
193
  ...[{ obj: 'ect' }, 0, false, ['array']].map((invalid) => audit(
196
194
  // TODO: convert to MUST after watershed
197
195
  `SHOULD use 400 status code on ${extendedTypeof(invalid)} {query} parameter when accepting application/graphql-response+json`, async () => {
198
- const res = await fetchFn(opts.url, {
196
+ const res = await fetchFn(await getUrl(opts.url), {
199
197
  method: 'POST',
200
198
  headers: {
201
199
  'content-type': 'application/json',
@@ -208,7 +206,7 @@ export function serverAudits(opts) {
208
206
  assert('Status code', res.status).toBe(400);
209
207
  })),
210
208
  ...[{ obj: 'ect' }, 0, false, ['array']].map((invalid) => audit(`SHOULD use 200 status code with errors field on ${extendedTypeof(invalid)} {query} parameter when accepting application/json`, async () => {
211
- const res = await fetchFn(opts.url, {
209
+ const res = await fetchFn(await getUrl(opts.url), {
212
210
  method: 'POST',
213
211
  headers: {
214
212
  'content-type': 'application/json',
@@ -224,7 +222,7 @@ export function serverAudits(opts) {
224
222
  audit(
225
223
  // TODO: convert to MUST after watershed
226
224
  'SHOULD allow string {query} parameter when accepting application/graphql-response+json', async () => {
227
- const res = await fetchFn(opts.url, {
225
+ const res = await fetchFn(await getUrl(opts.url), {
228
226
  method: 'POST',
229
227
  headers: {
230
228
  'content-type': 'application/json',
@@ -237,7 +235,7 @@ export function serverAudits(opts) {
237
235
  assert('Status code', res.status).toBe(200);
238
236
  }),
239
237
  audit('MUST allow string {query} parameter when accepting application/json', async () => {
240
- const res = await fetchFn(opts.url, {
238
+ const res = await fetchFn(await getUrl(opts.url), {
241
239
  method: 'POST',
242
240
  headers: {
243
241
  'content-type': 'application/json',
@@ -253,7 +251,7 @@ export function serverAudits(opts) {
253
251
  ...[{ obj: 'ect' }, 0, false, ['array']].map((invalid) => audit(
254
252
  // TODO: convert to MUST after watershed
255
253
  `SHOULD use 400 status code on ${extendedTypeof(invalid)} {operationName} parameter when accepting application/graphql-response+json`, async () => {
256
- const res = await fetchFn(opts.url, {
254
+ const res = await fetchFn(await getUrl(opts.url), {
257
255
  method: 'POST',
258
256
  headers: {
259
257
  'content-type': 'application/json',
@@ -267,7 +265,7 @@ export function serverAudits(opts) {
267
265
  assert('Status code', res.status).toBe(400);
268
266
  })),
269
267
  ...[{ obj: 'ect' }, 0, false, ['array']].map((invalid) => audit(`SHOULD use 200 status code with errors field on ${extendedTypeof(invalid)} {operationName} parameter when accepting application/json`, async () => {
270
- const res = await fetchFn(opts.url, {
268
+ const res = await fetchFn(await getUrl(opts.url), {
271
269
  method: 'POST',
272
270
  headers: {
273
271
  'content-type': 'application/json',
@@ -284,7 +282,7 @@ export function serverAudits(opts) {
284
282
  audit(
285
283
  // TODO: convert to MUST after watershed
286
284
  'SHOULD allow string {operationName} parameter when accepting application/graphql-response+json', async () => {
287
- const res = await fetchFn(opts.url, {
285
+ const res = await fetchFn(await getUrl(opts.url), {
288
286
  method: 'POST',
289
287
  headers: {
290
288
  'content-type': 'application/json',
@@ -298,7 +296,7 @@ export function serverAudits(opts) {
298
296
  assert('Status code', res.status).toBe(200);
299
297
  }),
300
298
  audit('MUST allow string {operationName} parameter when accepting application/json', async () => {
301
- const res = await fetchFn(opts.url, {
299
+ const res = await fetchFn(await getUrl(opts.url), {
302
300
  method: 'POST',
303
301
  headers: {
304
302
  'content-type': 'application/json',
@@ -315,7 +313,7 @@ export function serverAudits(opts) {
315
313
  ...['string', 0, false, ['array']].map((invalid) => audit(
316
314
  // TODO: convert to MUST after watershed
317
315
  `SHOULD use 400 status code on ${extendedTypeof(invalid)} {variables} parameter when accepting application/graphql-response+json`, async () => {
318
- const res = await fetchFn(opts.url, {
316
+ const res = await fetchFn(await getUrl(opts.url), {
319
317
  method: 'POST',
320
318
  headers: {
321
319
  'content-type': 'application/json',
@@ -329,7 +327,7 @@ export function serverAudits(opts) {
329
327
  assert('Status code', res.status).toBe(400);
330
328
  })),
331
329
  ...['string', 0, false, ['array']].map((invalid) => audit(`SHOULD use 200 status code with errors field on ${extendedTypeof(invalid)} {variables} parameter when accepting application/json`, async () => {
332
- const res = await fetchFn(opts.url, {
330
+ const res = await fetchFn(await getUrl(opts.url), {
333
331
  method: 'POST',
334
332
  headers: {
335
333
  'content-type': 'application/json',
@@ -346,7 +344,7 @@ export function serverAudits(opts) {
346
344
  audit(
347
345
  // TODO: convert to MUST after watershed
348
346
  'SHOULD allow map {variables} parameter when accepting application/graphql-response+json', async () => {
349
- const res = await fetchFn(opts.url, {
347
+ const res = await fetchFn(await getUrl(opts.url), {
350
348
  method: 'POST',
351
349
  headers: {
352
350
  'content-type': 'application/json',
@@ -360,7 +358,7 @@ export function serverAudits(opts) {
360
358
  assert('Status code', res.status).toBe(200);
361
359
  }),
362
360
  audit('MUST allow map {variables} parameter when accepting application/json', async () => {
363
- const res = await fetchFn(opts.url, {
361
+ const res = await fetchFn(await getUrl(opts.url), {
364
362
  method: 'POST',
365
363
  headers: {
366
364
  'content-type': 'application/json',
@@ -375,7 +373,7 @@ export function serverAudits(opts) {
375
373
  assert('Execution result', await assertBodyAsExecutionResult(res)).notToHaveProperty('errors');
376
374
  }),
377
375
  audit('MAY allow URL-encoded JSON string {variables} parameter in GETs when accepting application/graphql-response+json', async () => {
378
- const url = new URL(opts.url);
376
+ const url = new URL(await getUrl(opts.url));
379
377
  url.searchParams.set('query', 'query Type($name: String!) { __type(name: $name) { name } }');
380
378
  url.searchParams.set('variables', JSON.stringify({ name: 'sometype' }));
381
379
  const res = await fetchFn(url.toString(), {
@@ -387,7 +385,7 @@ export function serverAudits(opts) {
387
385
  assert('Status code', res.status).toBe(200);
388
386
  }),
389
387
  audit('MAY allow URL-encoded JSON string {variables} parameter in GETs when accepting application/json', async () => {
390
- const url = new URL(opts.url);
388
+ const url = new URL(await getUrl(opts.url));
391
389
  url.searchParams.set('query', 'query Type($name: String!) { __type(name: $name) { name } }');
392
390
  url.searchParams.set('variables', JSON.stringify({ name: 'sometype' }));
393
391
  const res = await fetchFn(url.toString(), {
@@ -402,7 +400,7 @@ export function serverAudits(opts) {
402
400
  ...['string', 0, false, ['array']].map((invalid) => audit(
403
401
  // TODO: convert to MUST after watershed
404
402
  `SHOULD use 400 status code on ${extendedTypeof(invalid)} {extensions} parameter when accepting application/graphql-response+json`, async () => {
405
- const res = await fetchFn(opts.url, {
403
+ const res = await fetchFn(await getUrl(opts.url), {
406
404
  method: 'POST',
407
405
  headers: {
408
406
  'content-type': 'application/json',
@@ -416,7 +414,7 @@ export function serverAudits(opts) {
416
414
  assert('Status code', res.status).toBe(400);
417
415
  })),
418
416
  ...['string', 0, false, ['array']].map((invalid) => audit(`SHOULD use 200 status code with errors field on ${extendedTypeof(invalid)} {extensions} parameter when accepting application/json`, async () => {
419
- const res = await fetchFn(opts.url, {
417
+ const res = await fetchFn(await getUrl(opts.url), {
420
418
  method: 'POST',
421
419
  headers: {
422
420
  'content-type': 'application/json',
@@ -433,7 +431,7 @@ export function serverAudits(opts) {
433
431
  audit(
434
432
  // TODO: convert to MUST after watershed
435
433
  'SHOULD allow map {extensions} parameter when accepting application/graphql-response+json', async () => {
436
- const res = await fetchFn(opts.url, {
434
+ const res = await fetchFn(await getUrl(opts.url), {
437
435
  method: 'POST',
438
436
  headers: {
439
437
  'content-type': 'application/json',
@@ -447,7 +445,7 @@ export function serverAudits(opts) {
447
445
  assert('Status code', res.status).toBe(200);
448
446
  }),
449
447
  audit('MUST allow map {extensions} parameter when accepting application/json', async () => {
450
- const res = await fetchFn(opts.url, {
448
+ const res = await fetchFn(await getUrl(opts.url), {
451
449
  method: 'POST',
452
450
  headers: {
453
451
  'content-type': 'application/json',
@@ -464,7 +462,7 @@ export function serverAudits(opts) {
464
462
  // TODO: audit('MUST accept a map for the {extensions} parameter'),
465
463
  // Response application/json
466
464
  audit('SHOULD use 200 status code on JSON parsing failure when accepting application/json', async () => {
467
- const res = await fetchFn(opts.url, {
465
+ const res = await fetchFn(await getUrl(opts.url), {
468
466
  method: 'POST',
469
467
  headers: {
470
468
  'content-type': 'application/json',
@@ -475,7 +473,7 @@ export function serverAudits(opts) {
475
473
  assert('Status code', res.status).toBe(200);
476
474
  }),
477
475
  audit('SHOULD use 200 status code if parameters are invalid when accepting application/json', async () => {
478
- const res = await fetchFn(opts.url, {
476
+ const res = await fetchFn(await getUrl(opts.url), {
479
477
  method: 'POST',
480
478
  headers: {
481
479
  'content-type': 'application/json',
@@ -488,7 +486,7 @@ export function serverAudits(opts) {
488
486
  assert('Status code', res.status).toBe(200);
489
487
  }),
490
488
  audit('SHOULD use 200 status code on document parsing failure when accepting application/json', async () => {
491
- const res = await fetchFn(opts.url, {
489
+ const res = await fetchFn(await getUrl(opts.url), {
492
490
  method: 'POST',
493
491
  headers: {
494
492
  'content-type': 'application/json',
@@ -499,7 +497,7 @@ export function serverAudits(opts) {
499
497
  assert('Status code', res.status).toBe(200);
500
498
  }),
501
499
  audit('SHOULD use 200 status code on document validation failure when accepting application/json', async () => {
502
- const res = await fetchFn(opts.url, {
500
+ const res = await fetchFn(await getUrl(opts.url), {
503
501
  method: 'POST',
504
502
  headers: {
505
503
  'content-type': 'application/json',
@@ -515,7 +513,7 @@ export function serverAudits(opts) {
515
513
  audit(
516
514
  // TODO: convert to MUST after watershed
517
515
  'SHOULD use 4xx or 5xx status codes on JSON parsing failure when accepting application/graphql-response+json', async () => {
518
- const res = await fetchFn(opts.url, {
516
+ const res = await fetchFn(await getUrl(opts.url), {
519
517
  method: 'POST',
520
518
  headers: {
521
519
  'content-type': 'application/json',
@@ -526,7 +524,7 @@ export function serverAudits(opts) {
526
524
  assert('Status code', res.status).toBeBetween(400, 499);
527
525
  }),
528
526
  audit('SHOULD use 400 status code on JSON parsing failure when accepting application/graphql-response+json', async () => {
529
- const res = await fetchFn(opts.url, {
527
+ const res = await fetchFn(await getUrl(opts.url), {
530
528
  method: 'POST',
531
529
  headers: {
532
530
  'content-type': 'application/json',
@@ -537,7 +535,7 @@ export function serverAudits(opts) {
537
535
  assert('Status code', res.status).toBe(400);
538
536
  }),
539
537
  audit('SHOULD not contain the data entry on JSON parsing failure when accepting application/graphql-response+json', async () => {
540
- const res = await fetchFn(opts.url, {
538
+ const res = await fetchFn(await getUrl(opts.url), {
541
539
  method: 'POST',
542
540
  headers: {
543
541
  'content-type': 'application/json',
@@ -550,7 +548,7 @@ export function serverAudits(opts) {
550
548
  audit(
551
549
  // TODO: convert to MUST after watershed
552
550
  'SHOULD use 4xx or 5xx status codes if parameters are invalid when accepting application/graphql-response+json', async () => {
553
- const res = await fetchFn(opts.url, {
551
+ const res = await fetchFn(await getUrl(opts.url), {
554
552
  method: 'POST',
555
553
  headers: {
556
554
  'content-type': 'application/json',
@@ -563,7 +561,7 @@ export function serverAudits(opts) {
563
561
  assert('Status code', res.status).toBeBetween(400, 599);
564
562
  }),
565
563
  audit('SHOULD use 400 status code if parameters are invalid when accepting application/graphql-response+json', async () => {
566
- const res = await fetchFn(opts.url, {
564
+ const res = await fetchFn(await getUrl(opts.url), {
567
565
  method: 'POST',
568
566
  headers: {
569
567
  'content-type': 'application/json',
@@ -576,7 +574,7 @@ export function serverAudits(opts) {
576
574
  assert('Status code', res.status).toBe(400);
577
575
  }),
578
576
  audit('SHOULD not contain the data entry if parameters are invalid when accepting application/graphql-response+json', async () => {
579
- const res = await fetchFn(opts.url, {
577
+ const res = await fetchFn(await getUrl(opts.url), {
580
578
  method: 'POST',
581
579
  headers: {
582
580
  'content-type': 'application/json',
@@ -591,7 +589,7 @@ export function serverAudits(opts) {
591
589
  audit(
592
590
  // TODO: convert to MUST after watershed
593
591
  'SHOULD use 4xx or 5xx status codes on document parsing failure when accepting application/graphql-response+json', async () => {
594
- const res = await fetchFn(opts.url, {
592
+ const res = await fetchFn(await getUrl(opts.url), {
595
593
  method: 'POST',
596
594
  headers: {
597
595
  'content-type': 'application/json',
@@ -604,7 +602,7 @@ export function serverAudits(opts) {
604
602
  assert('Status code', res.status).toBeBetween(400, 599);
605
603
  }),
606
604
  audit('SHOULD use 400 status code on document parsing failure when accepting application/graphql-response+json', async () => {
607
- const res = await fetchFn(opts.url, {
605
+ const res = await fetchFn(await getUrl(opts.url), {
608
606
  method: 'POST',
609
607
  headers: {
610
608
  'content-type': 'application/json',
@@ -617,7 +615,7 @@ export function serverAudits(opts) {
617
615
  assert('Status code', res.status).toBe(400);
618
616
  }),
619
617
  audit('SHOULD not contain the data entry on document parsing failure when accepting application/graphql-response+json', async () => {
620
- const res = await fetchFn(opts.url, {
618
+ const res = await fetchFn(await getUrl(opts.url), {
621
619
  method: 'POST',
622
620
  headers: {
623
621
  'content-type': 'application/json',
@@ -632,7 +630,7 @@ export function serverAudits(opts) {
632
630
  audit(
633
631
  // TODO: convert to MUST after watershed
634
632
  'SHOULD use 4xx or 5xx status codes on document validation failure when accepting application/graphql-response+json', async () => {
635
- const res = await fetchFn(opts.url, {
633
+ const res = await fetchFn(await getUrl(opts.url), {
636
634
  method: 'POST',
637
635
  headers: {
638
636
  'content-type': 'application/json',
@@ -645,7 +643,7 @@ export function serverAudits(opts) {
645
643
  assert('Status code', res.status).toBeBetween(400, 599);
646
644
  }),
647
645
  audit('SHOULD use 400 status code on document validation failure when accepting application/graphql-response+json', async () => {
648
- const res = await fetchFn(opts.url, {
646
+ const res = await fetchFn(await getUrl(opts.url), {
649
647
  method: 'POST',
650
648
  headers: {
651
649
  'content-type': 'application/json',
@@ -658,7 +656,7 @@ export function serverAudits(opts) {
658
656
  assert('Status code', res.status).toBe(400);
659
657
  }),
660
658
  audit('SHOULD not contain the data entry on document validation failure when accepting application/graphql-response+json', async () => {
661
- const res = await fetchFn(opts.url, {
659
+ const res = await fetchFn(await getUrl(opts.url), {
662
660
  method: 'POST',
663
661
  headers: {
664
662
  'content-type': 'application/json',
@@ -689,3 +687,10 @@ export async function auditServer(opts) {
689
687
  // audit tests will throw only on fatal errors, tests are contained within the AuditResult
690
688
  return await Promise.all(audits.map(({ fn }) => fn()));
691
689
  }
690
+ /** @private */
691
+ async function getUrl(url) {
692
+ if (typeof url === 'string') {
693
+ return url;
694
+ }
695
+ return await url();
696
+ }
package/lib/handler.js CHANGED
@@ -296,15 +296,16 @@ function getAcceptableMediaType(acceptHeader) {
296
296
  // TODO: handle the weight parameter "q"
297
297
  const [mediaType, ...params] = accept.split(';');
298
298
  const charset = (params === null || params === void 0 ? void 0 : params.find((param) => param.includes('charset='))) || 'charset=utf8'; // utf-8 is assumed when not specified;
299
- if (mediaType === 'application/json' && charset === 'charset=utf8') {
300
- acceptedMediaType = 'application/json';
299
+ if (mediaType === 'application/graphql-response+json' &&
300
+ charset === 'charset=utf8') {
301
+ acceptedMediaType = 'application/graphql-response+json';
301
302
  break;
302
303
  }
303
- if ((mediaType === 'application/graphql-response+json' ||
304
+ if ((mediaType === 'application/json' ||
304
305
  mediaType === 'application/*' ||
305
306
  mediaType === '*/*') &&
306
307
  charset === 'charset=utf8') {
307
- acceptedMediaType = 'application/graphql-response+json';
308
+ acceptedMediaType = 'application/json';
308
309
  break;
309
310
  }
310
311
  }
package/lib/handler.mjs CHANGED
@@ -291,15 +291,16 @@ export function getAcceptableMediaType(acceptHeader) {
291
291
  // TODO: handle the weight parameter "q"
292
292
  const [mediaType, ...params] = accept.split(';');
293
293
  const charset = (params === null || params === void 0 ? void 0 : params.find((param) => param.includes('charset='))) || 'charset=utf8'; // utf-8 is assumed when not specified;
294
- if (mediaType === 'application/json' && charset === 'charset=utf8') {
295
- acceptedMediaType = 'application/json';
294
+ if (mediaType === 'application/graphql-response+json' &&
295
+ charset === 'charset=utf8') {
296
+ acceptedMediaType = 'application/graphql-response+json';
296
297
  break;
297
298
  }
298
- if ((mediaType === 'application/graphql-response+json' ||
299
+ if ((mediaType === 'application/json' ||
299
300
  mediaType === 'application/*' ||
300
301
  mediaType === '*/*') &&
301
302
  charset === 'charset=utf8') {
302
- acceptedMediaType = 'application/graphql-response+json';
303
+ acceptedMediaType = 'application/json';
303
304
  break;
304
305
  }
305
306
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphql-http",
3
- "version": "1.7.1",
3
+ "version": "1.8.0",
4
4
  "description": "Simple, pluggable, zero-dependency, GraphQL over HTTP Protocol compliant server and client",
5
5
  "keywords": [
6
6
  "graphql",
Binary file