diff --git a/src/registry/mod.rs b/src/registry/mod.rs index 71eedf59..db06d275 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -300,6 +300,8 @@ pub struct Registry { pub query_type: String, pub mutation_type: Option, pub subscription_type: Option, + pub disable_introspection: bool, + pub enable_federation: bool, } impl Registry { diff --git a/src/schema.rs b/src/schema.rs index bd9e875e..551c6e32 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -33,7 +33,6 @@ pub struct SchemaBuilder { complexity: Option, depth: Option, extensions: Vec>, - enable_federation: bool, } impl SchemaBuilder { @@ -47,7 +46,7 @@ impl SchemaBuilder /// Disable introspection queries. pub fn disable_introspection(mut self) -> Self { - self.query.disable_introspection = true; + self.registry.disable_introspection = true; self } @@ -102,7 +101,7 @@ impl SchemaBuilder /// Enable federation, which is automatically enabled if the Query has least one entity definition. pub fn enable_federation(mut self) -> Self { - self.enable_federation = true; + self.registry.enable_federation = true; self } @@ -115,7 +114,7 @@ impl SchemaBuilder /// Build schema. pub fn finish(mut self) -> Schema { // federation - if self.enable_federation || self.registry.has_entities() { + if self.registry.enable_federation || self.registry.has_entities() { self.registry.create_federation_types(); } @@ -217,10 +216,7 @@ where ) -> SchemaBuilder { SchemaBuilder { validation_mode: ValidationMode::Strict, - query: QueryRoot { - inner: query, - disable_introspection: false, - }, + query: QueryRoot { inner: query }, mutation, subscription, registry: Self::create_registry(), @@ -228,7 +224,6 @@ where complexity: None, depth: None, extensions: Default::default(), - enable_federation: false, } } @@ -248,6 +243,8 @@ where } else { Some(Subscription::type_name().to_string()) }, + disable_introspection: false, + enable_federation: false, }; registry.add_directive(MetaDirective { diff --git a/src/types/query_root.rs b/src/types/query_root.rs index 6283eb9c..7139c9b3 100644 --- a/src/types/query_root.rs +++ b/src/types/query_root.rs @@ -19,7 +19,6 @@ struct Service { pub(crate) struct QueryRoot { pub(crate) inner: T, - pub(crate) disable_introspection: bool, } impl Type for QueryRoot { @@ -28,59 +27,63 @@ impl Type for QueryRoot { } fn create_type_info(registry: &mut registry::Registry) -> String { - let schema_type = __Schema::create_type_info(registry); let root = T::create_type_info(registry); - if let Some(registry::MetaType::Object { fields, .. }) = - registry.types.get_mut(T::type_name().as_ref()) - { - fields.insert( - "__schema".to_string(), - registry::MetaField { - name: "__schema".to_string(), - description: Some("Access the current type schema of this server."), - args: Default::default(), - ty: schema_type, - deprecation: None, - cache_control: Default::default(), - external: false, - requires: None, - provides: None, - visible: None, - compute_complexity: None, - }, - ); - fields.insert( - "__type".to_string(), - registry::MetaField { - name: "__type".to_string(), - description: Some("Request the type information of a single type."), - args: { - let mut args = IndexMap::new(); - args.insert( - "name", - registry::MetaInputValue { - name: "name", - description: None, - ty: "String!".to_string(), - default_value: None, - validator: None, - visible: None, - }, - ); - args + if !registry.disable_introspection { + let schema_type = __Schema::create_type_info(registry); + if let Some(registry::MetaType::Object { fields, .. }) = + registry.types.get_mut(T::type_name().as_ref()) + { + fields.insert( + "__schema".to_string(), + registry::MetaField { + name: "__schema".to_string(), + description: Some("Access the current type schema of this server."), + args: Default::default(), + ty: schema_type, + deprecation: None, + cache_control: Default::default(), + external: false, + requires: None, + provides: None, + visible: None, + compute_complexity: None, }, - ty: "__Type".to_string(), - deprecation: None, - cache_control: Default::default(), - external: false, - requires: None, - provides: None, - visible: None, - compute_complexity: None, - }, - ); + ); + + fields.insert( + "__type".to_string(), + registry::MetaField { + name: "__type".to_string(), + description: Some("Request the type information of a single type."), + args: { + let mut args = IndexMap::new(); + args.insert( + "name", + registry::MetaInputValue { + name: "name", + description: None, + ty: "String!".to_string(), + default_value: None, + validator: None, + visible: None, + }, + ); + args + }, + ty: "__Type".to_string(), + deprecation: None, + cache_control: Default::default(), + external: false, + requires: None, + provides: None, + visible: None, + compute_complexity: None, + }, + ); + } } + root } } @@ -88,59 +91,60 @@ impl Type for QueryRoot { #[async_trait::async_trait] impl ContainerType for QueryRoot { async fn resolve_field(&self, ctx: &Context<'_>) -> ServerResult> { - if ctx.item.node.name.node == "__schema" { - if self.disable_introspection { - return Err(ServerError::new("Query introspection is disabled.").at(ctx.item.pos)); + if !ctx.schema_env.registry.disable_introspection { + if ctx.item.node.name.node == "__schema" { + let ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set); + return OutputType::resolve( + &__Schema { + registry: &ctx.schema_env.registry, + }, + &ctx_obj, + ctx.item, + ) + .await + .map(Some); + } else if ctx.item.node.name.node == "__type" { + let type_name: String = ctx.param_value("name", None)?; + let ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set); + return OutputType::resolve( + &ctx.schema_env + .registry + .types + .get(&type_name) + .filter(|ty| ty.is_visible(ctx)) + .map(|ty| __Type::new_simple(&ctx.schema_env.registry, ty)), + &ctx_obj, + ctx.item, + ) + .await + .map(Some); } + } - let ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set); - return OutputType::resolve( - &__Schema { - registry: &ctx.schema_env.registry, - }, - &ctx_obj, - ctx.item, - ) - .await - .map(Some); - } else if ctx.item.node.name.node == "__type" { - let type_name: String = ctx.param_value("name", None)?; - let ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set); - return OutputType::resolve( - &ctx.schema_env - .registry - .types - .get(&type_name) - .filter(|ty| ty.is_visible(ctx)) - .map(|ty| __Type::new_simple(&ctx.schema_env.registry, ty)), - &ctx_obj, - ctx.item, - ) - .await - .map(Some); - } else if ctx.item.node.name.node == "_entities" { - let representations: Vec = ctx.param_value("representations", None)?; - let mut res = Vec::new(); - for item in representations { - res.push( - self.inner - .find_entity(ctx, &item.0) - .await? - .ok_or_else(|| ServerError::new("Entity not found.").at(ctx.item.pos))?, - ); + if ctx.schema_env.registry.enable_federation || ctx.schema_env.registry.has_entities() { + if ctx.item.node.name.node == "_entities" { + let representations: Vec = ctx.param_value("representations", None)?; + let mut res = Vec::new(); + for item in representations { + res.push( + self.inner.find_entity(ctx, &item.0).await?.ok_or_else(|| { + ServerError::new("Entity not found.").at(ctx.item.pos) + })?, + ); + } + return Ok(Some(Value::List(res))); + } else if ctx.item.node.name.node == "_service" { + let ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set); + return OutputType::resolve( + &Service { + sdl: Some(ctx.schema_env.registry.export_sdl(true)), + }, + &ctx_obj, + ctx.item, + ) + .await + .map(Some); } - return Ok(Some(Value::List(res))); - } else if ctx.item.node.name.node == "_service" { - let ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set); - return OutputType::resolve( - &Service { - sdl: Some(ctx.schema_env.registry.export_sdl(true)), - }, - &ctx_obj, - ctx.item, - ) - .await - .map(Some); } self.inner.resolve_field(ctx).await