@@ -3,6 +3,7 @@ use crate::data::graphql::ext::{DirectiveExt, DirectiveFinder, DocumentExt, Type
3
3
use crate :: data:: store:: ValueType ;
4
4
use crate :: data:: subgraph:: { DeploymentHash , SubgraphName } ;
5
5
use crate :: prelude:: {
6
+ lazy_static,
6
7
q:: Value ,
7
8
s:: { self , Definition , InterfaceType , ObjectType , TypeDefinition , * } ,
8
9
} ;
@@ -355,8 +356,15 @@ pub struct ApiSchema {
355
356
}
356
357
357
358
impl ApiSchema {
358
- /// `api_schema` will typically come from `fn api_schema` in the graphql crate.
359
- pub fn from_api_schema ( api_schema : Schema ) -> Result < Self , anyhow:: Error > {
359
+ /// `api_schema` will typically come from `fn api_schema` in the graphql
360
+ /// crate.
361
+ ///
362
+ /// In addition, the API schema has an introspection schema mixed into
363
+ /// `api_schema`. In particular, the `Query` type has fields called
364
+ /// `__schema` and `__type`
365
+ pub fn from_api_schema ( mut api_schema : Schema ) -> Result < Self , anyhow:: Error > {
366
+ add_introspection_schema ( & mut api_schema. document ) ;
367
+
360
368
let query_type = api_schema
361
369
. document
362
370
. get_root_query_type ( )
@@ -397,6 +405,69 @@ impl ApiSchema {
397
405
}
398
406
}
399
407
408
+ fn add_introspection_schema ( schema : & mut Document ) {
409
+ lazy_static ! {
410
+ static ref INTROSPECTION_SCHEMA : Document = {
411
+ let schema = include_str!( "introspection.graphql" ) ;
412
+ parse_schema( schema) . expect( "the schema `introspection.graphql` is invalid" )
413
+ } ;
414
+ }
415
+
416
+ fn introspection_fields ( ) -> Vec < Field > {
417
+ // Generate fields for the root query fields in an introspection schema,
418
+ // the equivalent of the fields of the `Query` type:
419
+ //
420
+ // type Query {
421
+ // __schema: __Schema!
422
+ // __type(name: String!): __Type
423
+ // }
424
+
425
+ let type_args = vec ! [ InputValue {
426
+ position: Pos :: default ( ) ,
427
+ description: None ,
428
+ name: "name" . to_string( ) ,
429
+ value_type: Type :: NonNullType ( Box :: new( Type :: NamedType ( "String" . to_string( ) ) ) ) ,
430
+ default_value: None ,
431
+ directives: vec![ ] ,
432
+ } ] ;
433
+
434
+ vec ! [
435
+ Field {
436
+ position: Pos :: default ( ) ,
437
+ description: None ,
438
+ name: "__schema" . to_string( ) ,
439
+ arguments: vec![ ] ,
440
+ field_type: Type :: NonNullType ( Box :: new( Type :: NamedType ( "__Schema" . to_string( ) ) ) ) ,
441
+ directives: vec![ ] ,
442
+ } ,
443
+ Field {
444
+ position: Pos :: default ( ) ,
445
+ description: None ,
446
+ name: "__type" . to_string( ) ,
447
+ arguments: type_args,
448
+ field_type: Type :: NamedType ( "__Type" . to_string( ) ) ,
449
+ directives: vec![ ] ,
450
+ } ,
451
+ ]
452
+ }
453
+
454
+ schema
455
+ . definitions
456
+ . extend ( INTROSPECTION_SCHEMA . definitions . iter ( ) . cloned ( ) ) ;
457
+
458
+ let query_type = schema
459
+ . definitions
460
+ . iter_mut ( )
461
+ . filter_map ( |d| match d {
462
+ Definition :: TypeDefinition ( TypeDefinition :: Object ( t) ) if t. name == "Query" => Some ( t) ,
463
+ _ => None ,
464
+ } )
465
+ . peekable ( )
466
+ . next ( )
467
+ . expect ( "no root `Query` in the schema" ) ;
468
+ query_type. fields . append ( & mut introspection_fields ( ) ) ;
469
+ }
470
+
400
471
/// A validated and preprocessed GraphQL schema for a subgraph.
401
472
#[ derive( Clone , Debug , PartialEq ) ]
402
473
pub struct Schema {
0 commit comments