@@ -3,6 +3,7 @@ use crate::data::graphql::ext::{DirectiveExt, DirectiveFinder, DocumentExt, Type
33use crate :: data:: store:: ValueType ;
44use crate :: data:: subgraph:: { DeploymentHash , SubgraphName } ;
55use crate :: prelude:: {
6+ lazy_static,
67 q:: Value ,
78 s:: { self , Definition , InterfaceType , ObjectType , TypeDefinition , * } ,
89} ;
@@ -355,8 +356,15 @@ pub struct ApiSchema {
355356}
356357
357358impl 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+
360368 let query_type = api_schema
361369 . document
362370 . get_root_query_type ( )
@@ -397,6 +405,69 @@ impl ApiSchema {
397405 }
398406}
399407
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+
400471/// A validated and preprocessed GraphQL schema for a subgraph.
401472#[ derive( Clone , Debug , PartialEq ) ]
402473pub struct Schema {
0 commit comments