@@ -15,6 +15,7 @@ import {
15
15
import type { Dispatch } from 'react' ;
16
16
import type { StateCreator } from 'zustand' ;
17
17
import type { SlicesWithActions , SchemaReference } from '../types' ;
18
+ import { tryParseJSONC } from '../utility' ;
18
19
19
20
type MaybeGraphQLSchema = GraphQLSchema | null | undefined ;
20
21
@@ -59,7 +60,9 @@ export const createSchemaSlice: CreateSchemaSlice = initial => (set, get) => ({
59
60
onSchemaChange,
60
61
headerEditor,
61
62
fetcher,
62
- ...rest
63
+ inputValueDeprecation,
64
+ introspectionQueryName,
65
+ schemaDescription,
63
66
} = get ( ) ;
64
67
65
68
/**
@@ -71,67 +74,57 @@ export const createSchemaSlice: CreateSchemaSlice = initial => (set, get) => ({
71
74
return ;
72
75
}
73
76
const counter = requestCounter + 1 ;
74
- set ( { requestCounter : counter } ) ;
75
-
77
+ set ( { requestCounter : counter , isIntrospecting : true , fetchError : null } ) ;
76
78
try {
77
- const currentHeaders = headerEditor ?. getValue ( ) ;
78
- const parsedHeaders = parseHeaderString ( currentHeaders ) ;
79
- if ( ! parsedHeaders . isValidJSON ) {
80
- set ( { fetchError : 'Introspection failed as headers are invalid.' } ) ;
81
- return ;
79
+ let headers : Record < string , unknown > | undefined ;
80
+ try {
81
+ headers = tryParseJSONC ( headerEditor ?. getValue ( ) ) ;
82
+ } catch ( error ) {
83
+ throw new Error (
84
+ `Introspection failed. Request headers ${ error instanceof Error ? error . message : error } ` ,
85
+ ) ;
82
86
}
83
87
84
- const fetcherOpts : FetcherOpts = parsedHeaders . headers
85
- ? { headers : parsedHeaders . headers }
86
- : { } ;
87
-
88
+ const fetcherOpts : FetcherOpts = headers ? { headers } : { } ;
88
89
/**
89
90
* Get an introspection query for settings given via props
90
91
*/
91
- const {
92
- introspectionQuery,
93
- introspectionQueryName,
94
- introspectionQuerySansSubscriptions,
95
- } = generateIntrospectionQuery ( rest ) ;
96
- const fetch = fetcherReturnToPromise (
97
- fetcher (
98
- {
99
- query : introspectionQuery ,
100
- operationName : introspectionQueryName ,
101
- } ,
102
- fetcherOpts ,
103
- ) ,
104
- ) ;
105
-
106
- if ( ! isPromise ( fetch ) ) {
107
- set ( {
108
- fetchError : 'Fetcher did not return a Promise for introspection.' ,
109
- } ) ;
110
- return ;
111
- }
112
- set ( { isIntrospecting : true , fetchError : null } ) ;
113
- let result = await fetch ;
92
+ const introspectionQuery = getIntrospectionQuery ( {
93
+ inputValueDeprecation,
94
+ schemaDescription,
95
+ } ) ;
114
96
115
- if ( typeof result !== 'object' || ! ( 'data' in result ) ) {
116
- // Try the stock introspection query first, falling back on the
117
- // sans-subscriptions query for services which do not yet support it.
118
- const fetch2 = fetcherReturnToPromise (
97
+ function doIntrospection ( query : string ) {
98
+ const fetch = fetcherReturnToPromise (
119
99
fetcher (
120
- {
121
- query : introspectionQuerySansSubscriptions ,
122
- operationName : introspectionQueryName ,
123
- } ,
100
+ { query, operationName : introspectionQueryName } ,
124
101
fetcherOpts ,
125
102
) ,
126
103
) ;
127
- if ( ! isPromise ( fetch2 ) ) {
128
- throw new Error (
104
+ if ( ! isPromise ( fetch ) ) {
105
+ throw new TypeError (
129
106
'Fetcher did not return a Promise for introspection.' ,
130
107
) ;
131
108
}
132
- result = await fetch2 ;
109
+ return fetch ;
133
110
}
134
111
112
+ const normalizedQuery =
113
+ introspectionQueryName === 'IntrospectionQuery'
114
+ ? introspectionQuery
115
+ : introspectionQuery . replace (
116
+ 'query IntrospectionQuery' ,
117
+ `query ${ introspectionQueryName } ` ,
118
+ ) ;
119
+ let result = await doIntrospection ( normalizedQuery ) ;
120
+
121
+ if ( typeof result !== 'object' || ! ( 'data' in result ) ) {
122
+ // Try the stock introspection query first, falling back on the
123
+ // sans-subscriptions query for services which do not yet support it.
124
+ result = await doIntrospection (
125
+ introspectionQuery . replace ( 'subscriptionType { name }' , '' ) ,
126
+ ) ;
127
+ }
135
128
set ( { isIntrospecting : false } ) ;
136
129
let introspectionData : IntrospectionQuery | undefined ;
137
130
if ( result . data && '__schema' in result . data ) {
@@ -160,9 +153,12 @@ export const createSchemaSlice: CreateSchemaSlice = initial => (set, get) => ({
160
153
if ( counter !== get ( ) . requestCounter ) {
161
154
return ;
162
155
}
156
+ if ( error instanceof Error ) {
157
+ delete error . stack ;
158
+ }
163
159
set ( {
164
- fetchError : formatError ( error ) ,
165
160
isIntrospecting : false ,
161
+ fetchError : formatError ( error ) ,
166
162
} ) ;
167
163
}
168
164
} ,
@@ -233,7 +229,7 @@ export interface SchemaActions {
233
229
setSchemaReference : Dispatch < SchemaReference > ;
234
230
}
235
231
236
- export interface SchemaProps extends IntrospectionArgs {
232
+ export interface SchemaProps {
237
233
/**
238
234
* This prop can be used to skip validating the GraphQL schema. This applies
239
235
* to both schemas fetched via introspection and schemas explicitly passed
@@ -272,9 +268,7 @@ export interface SchemaProps extends IntrospectionArgs {
272
268
* run without a schema.
273
269
*/
274
270
schema ?: GraphQLSchema | IntrospectionQuery | null ;
275
- }
276
271
277
- interface IntrospectionArgs {
278
272
/**
279
273
* Can be used to set the equally named option for introspecting a GraphQL
280
274
* server.
@@ -297,45 +291,3 @@ interface IntrospectionArgs {
297
291
*/
298
292
schemaDescription ?: boolean ;
299
293
}
300
-
301
- function generateIntrospectionQuery ( {
302
- inputValueDeprecation,
303
- introspectionQueryName,
304
- schemaDescription,
305
- } : IntrospectionArgs ) {
306
- const query = getIntrospectionQuery ( {
307
- inputValueDeprecation,
308
- schemaDescription,
309
- } ) ;
310
- const introspectionQuery =
311
- introspectionQueryName === 'IntrospectionQuery'
312
- ? query
313
- : query . replace (
314
- 'query IntrospectionQuery' ,
315
- `query ${ introspectionQueryName } ` ,
316
- ) ;
317
- const introspectionQuerySansSubscriptions = query . replace (
318
- 'subscriptionType { name }' ,
319
- '' ,
320
- ) ;
321
-
322
- return {
323
- introspectionQueryName,
324
- introspectionQuery,
325
- introspectionQuerySansSubscriptions,
326
- } ;
327
- }
328
-
329
- function parseHeaderString ( headersString ?: string ) {
330
- let headers : Record < string , unknown > | null = null ;
331
- let isValidJSON = true ;
332
-
333
- try {
334
- if ( headersString ) {
335
- headers = JSON . parse ( headersString ) ;
336
- }
337
- } catch {
338
- isValidJSON = false ;
339
- }
340
- return { headers, isValidJSON } ;
341
- }
0 commit comments