graphql-http 1.6.1 → 1.7.1

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.
@@ -19,23 +19,25 @@ 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 url = new URL(opts.url);
23
- url.searchParams.set('query', '{ __typename }');
24
- const res = await fetchFn(url.toString(), {
22
+ const res = await fetchFn(opts.url, {
23
+ method: 'POST',
25
24
  headers: {
25
+ 'content-type': 'application/json',
26
26
  accept: 'application/graphql-response+json',
27
27
  },
28
+ body: JSON.stringify({ query: '{ __typename }' }),
28
29
  });
29
30
  (0, utils_1.assert)('Status code', res.status).toBe(200);
30
31
  (0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('application/graphql-response+json');
31
32
  }),
32
33
  (0, utils_1.audit)('MUST accept application/json and match the content-type', async () => {
33
- const url = new URL(opts.url);
34
- url.searchParams.set('query', '{ __typename }');
35
- const res = await fetchFn(url.toString(), {
34
+ const res = await fetchFn(opts.url, {
35
+ method: 'POST',
36
36
  headers: {
37
+ 'content-type': 'application/json',
37
38
  accept: 'application/json',
38
39
  },
40
+ body: JSON.stringify({ query: '{ __typename }' }),
39
41
  });
40
42
  (0, utils_1.assert)('Status code', res.status).toBe(200);
41
43
  (0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('application/json');
@@ -43,12 +45,13 @@ function serverAudits(opts) {
43
45
  (0, utils_1.audit)(
44
46
  // TODO: convert to MUST after watershed
45
47
  'SHOULD accept */* and use application/graphql-response+json for the content-type', async () => {
46
- const url = new URL(opts.url);
47
- url.searchParams.set('query', '{ __typename }');
48
- const res = await fetchFn(url.toString(), {
48
+ const res = await fetchFn(opts.url, {
49
+ method: 'POST',
49
50
  headers: {
51
+ 'content-type': 'application/json',
50
52
  accept: '*/*',
51
53
  },
54
+ body: JSON.stringify({ query: '{ __typename }' }),
52
55
  });
53
56
  (0, utils_1.assert)('Status code', res.status).toBe(200);
54
57
  (0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('application/graphql-response+json');
@@ -56,16 +59,24 @@ function serverAudits(opts) {
56
59
  (0, utils_1.audit)(
57
60
  // TODO: convert to MUST after watershed
58
61
  'SHOULD assume application/graphql-response+json content-type when accept is missing', async () => {
59
- const url = new URL(opts.url);
60
- url.searchParams.set('query', '{ __typename }');
61
- const res = await fetchFn(url.toString());
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
+ });
62
69
  (0, utils_1.assert)('Status code', res.status).toBe(200);
63
70
  (0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('application/graphql-response+json');
64
71
  }),
65
72
  (0, utils_1.audit)('MUST use utf-8 encoding when responding', async () => {
66
- const url = new URL(opts.url);
67
- url.searchParams.set('query', '{ __typename }');
68
- const res = await fetchFn(url.toString());
73
+ const res = await fetchFn(opts.url, {
74
+ method: 'POST',
75
+ headers: {
76
+ 'content-type': 'application/json',
77
+ },
78
+ body: JSON.stringify({ query: '{ __typename }' }),
79
+ });
69
80
  (0, utils_1.assert)('Status code', res.status).toBe(200);
70
81
  // has charset set to utf-8
71
82
  try {
@@ -87,24 +98,27 @@ function serverAudits(opts) {
87
98
  throw 'Body is not UTF-8 encoded';
88
99
  }
89
100
  }),
90
- (0, utils_1.audit)('MUST accept only utf-8 charset', async () => {
91
- const url = new URL(opts.url);
92
- url.searchParams.set('query', '{ __typename }');
93
- const res = await fetchFn(url.toString(), {
101
+ (0, utils_1.audit)('MUST accept utf-8 encoding', async () => {
102
+ const res = await fetchFn(opts.url, {
103
+ method: 'POST',
94
104
  headers: {
95
- accept: 'application/graphql-response+json; charset=iso-8859-1',
105
+ 'content-type': 'application/json; charset=utf-8',
96
106
  },
107
+ body: JSON.stringify({ query: '{ __typename }' }),
97
108
  });
98
- // application/json is 200 + errors
99
- const contentType = res.headers.get('content-type') || '';
100
- if (contentType.includes('application/json')) {
101
- (0, utils_1.assert)(`Content-Type ${contentType} status code`, res.status).toBe(200);
102
- (0, utils_1.assert)('Execution result', await (0, utils_1.assertBodyAsExecutionResult)(res)).toHaveProperty('errors');
103
- return;
104
- }
105
- // other content-types must be 4xx
106
- (0, utils_1.assert)(`Content-Type ${contentType} status code`, res.status).toBeGreaterThanOrEqual(400);
107
- (0, utils_1.assert)(`Content-Type ${contentType} status code`, res.status).toBeLessThanOrEqual(499);
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');
111
+ }),
112
+ (0, utils_1.audit)('MUST assume utf-8 if encoding is unspecified', async () => {
113
+ const res = await fetchFn(opts.url, {
114
+ method: 'POST',
115
+ headers: {
116
+ 'content-type': 'application/json',
117
+ },
118
+ body: JSON.stringify({ query: '{ __typename }' }),
119
+ });
120
+ (0, utils_1.assert)('Status code', res.status).toBe(200);
121
+ (0, utils_1.assert)('Content-Type header', res.headers.get('content-type')).toContain('utf-8');
108
122
  }),
109
123
  // Request
110
124
  (0, utils_1.audit)('MUST accept POST requests', async () => {
@@ -122,7 +136,8 @@ function serverAudits(opts) {
122
136
  (0, utils_1.assert)('Status code', res.status).toBe(200);
123
137
  }),
124
138
  // Request GET
125
- (0, utils_1.audit)('MUST NOT allow executing mutations on GET requests', async () => {
139
+ // TODO: this is a MUST if the server supports GET requests
140
+ (0, utils_1.audit)('MAY NOT allow executing mutations on GET requests', async () => {
126
141
  const url = new URL(opts.url);
127
142
  url.searchParams.set('query', 'mutation { __typename }');
128
143
  const res = await fetchFn(url.toString(), {
@@ -130,15 +145,14 @@ function serverAudits(opts) {
130
145
  accept: 'application/graphql-response+json',
131
146
  },
132
147
  });
133
- (0, utils_1.assert)('Status code', res.status).toBe(405);
148
+ (0, utils_1.assert)('Status code', res.status).toBeBetween(400, 499);
134
149
  }),
135
150
  // Request POST
136
151
  (0, utils_1.audit)('SHOULD respond with 4xx status code if content-type is not supplied on POST requests', async () => {
137
152
  const res = await fetchFn(opts.url, {
138
153
  method: 'POST',
139
154
  });
140
- (0, utils_1.assert)('Status code', res.status).toBeGreaterThanOrEqual(400);
141
- (0, utils_1.assert)('Status code', res.status).toBeLessThanOrEqual(499);
155
+ (0, utils_1.assert)('Status code', res.status).toBeBetween(400, 499);
142
156
  }),
143
157
  (0, utils_1.audit)('MUST accept application/json POST requests', async () => {
144
158
  const res = await fetchFn(opts.url, {
@@ -363,9 +377,7 @@ function serverAudits(opts) {
363
377
  (0, utils_1.assert)('Status code', res.status).toBe(200);
364
378
  (0, utils_1.assert)('Execution result', await (0, utils_1.assertBodyAsExecutionResult)(res)).notToHaveProperty('errors');
365
379
  }),
366
- (0, utils_1.audit)(
367
- // TODO: convert to MUST after watershed
368
- 'SHOULD allow URL-encoded JSON string {variables} parameter in GETs when accepting application/graphql-response+json', async () => {
380
+ (0, utils_1.audit)('MAY allow URL-encoded JSON string {variables} parameter in GETs when accepting application/graphql-response+json', async () => {
369
381
  const url = new URL(opts.url);
370
382
  url.searchParams.set('query', 'query Type($name: String!) { __type(name: $name) { name } }');
371
383
  url.searchParams.set('variables', JSON.stringify({ name: 'sometype' }));
@@ -377,7 +389,7 @@ function serverAudits(opts) {
377
389
  });
378
390
  (0, utils_1.assert)('Status code', res.status).toBe(200);
379
391
  }),
380
- (0, utils_1.audit)('MUST allow URL-encoded JSON string {variables} parameter in GETs when accepting application/json', async () => {
392
+ (0, utils_1.audit)('MAY allow URL-encoded JSON string {variables} parameter in GETs when accepting application/json', async () => {
381
393
  const url = new URL(opts.url);
382
394
  url.searchParams.set('query', 'query Type($name: String!) { __type(name: $name) { name } }');
383
395
  url.searchParams.set('variables', JSON.stringify({ name: 'sometype' }));
@@ -466,29 +478,39 @@ function serverAudits(opts) {
466
478
  (0, utils_1.assert)('Status code', res.status).toBe(200);
467
479
  }),
468
480
  (0, utils_1.audit)('SHOULD use 200 status code if parameters are invalid when accepting application/json', async () => {
469
- const url = new URL(opts.url);
470
- url.searchParams.set('qeury' /* typo */, '{ __typename }');
471
- const res = await fetchFn(url.toString(), {
472
- method: 'GET',
473
- headers: { accept: 'application/json' },
481
+ const res = await fetchFn(opts.url, {
482
+ method: 'POST',
483
+ headers: {
484
+ 'content-type': 'application/json',
485
+ accept: 'application/json',
486
+ },
487
+ body: JSON.stringify({
488
+ qeury: /* typo */ '{ __typename }',
489
+ }),
474
490
  });
475
491
  (0, utils_1.assert)('Status code', res.status).toBe(200);
476
492
  }),
477
493
  (0, utils_1.audit)('SHOULD use 200 status code on document parsing failure when accepting application/json', async () => {
478
- const url = new URL(opts.url);
479
- url.searchParams.set('query', '{');
480
- const res = await fetchFn(url.toString(), {
481
- method: 'GET',
482
- headers: { accept: 'application/json' },
494
+ const res = await fetchFn(opts.url, {
495
+ method: 'POST',
496
+ headers: {
497
+ 'content-type': 'application/json',
498
+ accept: 'application/json',
499
+ },
500
+ body: JSON.stringify({ query: '{' }),
483
501
  });
484
502
  (0, utils_1.assert)('Status code', res.status).toBe(200);
485
503
  }),
486
504
  (0, utils_1.audit)('SHOULD use 200 status code on document validation failure when accepting application/json', async () => {
487
- const url = new URL(opts.url);
488
- url.searchParams.set('query', '{ 8f31403dfe404bccbb0e835f2629c6a7 }'); // making sure the field doesnt exist
489
- const res = await fetchFn(url.toString(), {
490
- method: 'GET',
491
- headers: { accept: 'application/json' },
505
+ const res = await fetchFn(opts.url, {
506
+ method: 'POST',
507
+ headers: {
508
+ 'content-type': 'application/json',
509
+ accept: 'application/json',
510
+ },
511
+ body: JSON.stringify({
512
+ query: '{ 8f31403dfe404bccbb0e835f2629c6a7 }', // making sure the field doesnt exist
513
+ }),
492
514
  });
493
515
  (0, utils_1.assert)('Status code', res.status).toBe(200);
494
516
  }),
@@ -504,8 +526,7 @@ function serverAudits(opts) {
504
526
  },
505
527
  body: '{ "not a JSON',
506
528
  });
507
- (0, utils_1.assert)('Status code', res.status).toBeGreaterThanOrEqual(400);
508
- (0, utils_1.assert)('Status code', res.status).toBeLessThanOrEqual(599);
529
+ (0, utils_1.assert)('Status code', res.status).toBeBetween(400, 499);
509
530
  }),
510
531
  (0, utils_1.audit)('SHOULD use 400 status code on JSON parsing failure when accepting application/graphql-response+json', async () => {
511
532
  const res = await fetchFn(opts.url, {
@@ -532,90 +553,123 @@ function serverAudits(opts) {
532
553
  (0, utils_1.audit)(
533
554
  // TODO: convert to MUST after watershed
534
555
  'SHOULD use 4xx or 5xx status codes if parameters are invalid when accepting application/graphql-response+json', async () => {
535
- const url = new URL(opts.url);
536
- url.searchParams.set('qeury' /* typo */, '{ __typename }');
537
- const res = await fetchFn(url.toString(), {
538
- method: 'GET',
539
- headers: { accept: 'application/graphql-response+json' },
556
+ const res = await fetchFn(opts.url, {
557
+ method: 'POST',
558
+ headers: {
559
+ 'content-type': 'application/json',
560
+ accept: 'application/graphql-response+json',
561
+ },
562
+ body: JSON.stringify({
563
+ qeury /* typo */: '{ __typename }',
564
+ }),
540
565
  });
541
- (0, utils_1.assert)('Status code', res.status).toBeGreaterThanOrEqual(400);
542
- (0, utils_1.assert)('Status code', res.status).toBeLessThanOrEqual(599);
566
+ (0, utils_1.assert)('Status code', res.status).toBeBetween(400, 599);
543
567
  }),
544
568
  (0, utils_1.audit)('SHOULD use 400 status code if parameters are invalid when accepting application/graphql-response+json', async () => {
545
- const url = new URL(opts.url);
546
- url.searchParams.set('qeury' /* typo */, '{ __typename }');
547
- const res = await fetchFn(url.toString(), {
548
- method: 'GET',
549
- headers: { accept: 'application/graphql-response+json' },
569
+ const res = await fetchFn(opts.url, {
570
+ method: 'POST',
571
+ headers: {
572
+ 'content-type': 'application/json',
573
+ accept: 'application/graphql-response+json',
574
+ },
575
+ body: JSON.stringify({
576
+ qeury: /* typo */ '{ __typename }',
577
+ }),
550
578
  });
551
579
  (0, utils_1.assert)('Status code', res.status).toBe(400);
552
580
  }),
553
581
  (0, utils_1.audit)('SHOULD not contain the data entry if parameters are invalid when accepting application/graphql-response+json', async () => {
554
- const url = new URL(opts.url);
555
- url.searchParams.set('qeury' /* typo */, '{ __typename }');
556
- const res = await fetchFn(url.toString(), {
557
- method: 'GET',
558
- headers: { accept: 'application/graphql-response+json' },
582
+ const res = await fetchFn(opts.url, {
583
+ method: 'POST',
584
+ headers: {
585
+ 'content-type': 'application/json',
586
+ accept: 'application/graphql-response+json',
587
+ },
588
+ body: JSON.stringify({
589
+ qeury: /* typo */ '{ __typename }',
590
+ }),
559
591
  });
560
592
  (0, utils_1.assert)('Data entry', (await (0, utils_1.assertBodyAsExecutionResult)(res)).data).toBe(undefined);
561
593
  }),
562
594
  (0, utils_1.audit)(
563
595
  // TODO: convert to MUST after watershed
564
596
  'SHOULD use 4xx or 5xx status codes on document parsing failure when accepting application/graphql-response+json', async () => {
565
- const url = new URL(opts.url);
566
- url.searchParams.set('query', '{');
567
- const res = await fetchFn(url.toString(), {
568
- method: 'GET',
569
- headers: { accept: 'application/graphql-response+json' },
597
+ const res = await fetchFn(opts.url, {
598
+ method: 'POST',
599
+ headers: {
600
+ 'content-type': 'application/json',
601
+ accept: 'application/graphql-response+json',
602
+ },
603
+ body: JSON.stringify({
604
+ query: '{',
605
+ }),
570
606
  });
571
- (0, utils_1.assert)('Status code', res.status).toBeGreaterThanOrEqual(400);
572
- (0, utils_1.assert)('Status code', res.status).toBeLessThanOrEqual(599);
607
+ (0, utils_1.assert)('Status code', res.status).toBeBetween(400, 599);
573
608
  }),
574
609
  (0, utils_1.audit)('SHOULD use 400 status code on document parsing failure when accepting application/graphql-response+json', async () => {
575
- const url = new URL(opts.url);
576
- url.searchParams.set('query', '{');
577
- const res = await fetchFn(url.toString(), {
578
- method: 'GET',
579
- headers: { accept: 'application/graphql-response+json' },
610
+ const res = await fetchFn(opts.url, {
611
+ method: 'POST',
612
+ headers: {
613
+ 'content-type': 'application/json',
614
+ accept: 'application/graphql-response+json',
615
+ },
616
+ body: JSON.stringify({
617
+ query: '{',
618
+ }),
580
619
  });
581
620
  (0, utils_1.assert)('Status code', res.status).toBe(400);
582
621
  }),
583
622
  (0, utils_1.audit)('SHOULD not contain the data entry on document parsing failure when accepting application/graphql-response+json', async () => {
584
- const url = new URL(opts.url);
585
- url.searchParams.set('query', '{');
586
- const res = await fetchFn(url.toString(), {
587
- method: 'GET',
588
- headers: { accept: 'application/graphql-response+json' },
623
+ const res = await fetchFn(opts.url, {
624
+ method: 'POST',
625
+ headers: {
626
+ 'content-type': 'application/json',
627
+ accept: 'application/graphql-response+json',
628
+ },
629
+ body: JSON.stringify({
630
+ query: '{',
631
+ }),
589
632
  });
590
633
  (0, utils_1.assert)('Data entry', (await (0, utils_1.assertBodyAsExecutionResult)(res)).data).toBe(undefined);
591
634
  }),
592
635
  (0, utils_1.audit)(
593
636
  // TODO: convert to MUST after watershed
594
637
  'SHOULD use 4xx or 5xx status codes on document validation failure when accepting application/graphql-response+json', async () => {
595
- const url = new URL(opts.url);
596
- url.searchParams.set('query', '{ 8f31403dfe404bccbb0e835f2629c6a7 }'); // making sure the field doesnt exist
597
- const res = await fetchFn(url.toString(), {
598
- method: 'GET',
599
- headers: { accept: 'application/graphql-response+json' },
638
+ const res = await fetchFn(opts.url, {
639
+ method: 'POST',
640
+ headers: {
641
+ 'content-type': 'application/json',
642
+ accept: 'application/graphql-response+json',
643
+ },
644
+ body: JSON.stringify({
645
+ query: '{ 8f31403dfe404bccbb0e835f2629c6a7 }', // making sure the field doesnt exist
646
+ }),
600
647
  });
601
- (0, utils_1.assert)('Status code', res.status).toBeGreaterThanOrEqual(400);
602
- (0, utils_1.assert)('Status code', res.status).toBeLessThanOrEqual(599);
648
+ (0, utils_1.assert)('Status code', res.status).toBeBetween(400, 599);
603
649
  }),
604
650
  (0, utils_1.audit)('SHOULD use 400 status code on document validation failure when accepting application/graphql-response+json', async () => {
605
- const url = new URL(opts.url);
606
- url.searchParams.set('query', '{ 8f31403dfe404bccbb0e835f2629c6a7 }'); // making sure the field doesnt exist
607
- const res = await fetchFn(url.toString(), {
608
- method: 'GET',
609
- headers: { accept: 'application/graphql-response+json' },
651
+ const res = await fetchFn(opts.url, {
652
+ method: 'POST',
653
+ headers: {
654
+ 'content-type': 'application/json',
655
+ accept: 'application/graphql-response+json',
656
+ },
657
+ body: JSON.stringify({
658
+ query: '{ 8f31403dfe404bccbb0e835f2629c6a7 }', // making sure the field doesnt exist
659
+ }),
610
660
  });
611
661
  (0, utils_1.assert)('Status code', res.status).toBe(400);
612
662
  }),
613
663
  (0, utils_1.audit)('SHOULD not contain the data entry on document validation failure when accepting application/graphql-response+json', async () => {
614
- const url = new URL(opts.url);
615
- url.searchParams.set('query', '{ 8f31403dfe404bccbb0e835f2629c6a7 }'); // making sure the field doesnt exist
616
- const res = await fetchFn(url.toString(), {
617
- method: 'GET',
618
- headers: { accept: 'application/graphql-response+json' },
664
+ const res = await fetchFn(opts.url, {
665
+ method: 'POST',
666
+ headers: {
667
+ 'content-type': 'application/json',
668
+ accept: 'application/graphql-response+json',
669
+ },
670
+ body: JSON.stringify({
671
+ query: '{ 8f31403dfe404bccbb0e835f2629c6a7 }', // making sure the field doesnt exist
672
+ }),
619
673
  });
620
674
  (0, utils_1.assert)('Data entry', (await (0, utils_1.assertBodyAsExecutionResult)(res)).data).toBe(undefined);
621
675
  }),