Skip to content

Commit

Permalink
Add unsupported access to parsed schema document (#4715)
Browse files Browse the repository at this point in the history
Adds `PluginInit::unsupported_supergraph_schema` to allow plugins to
gain read only access to the parsed supergraph schema.

This eliminates the need for plugins to reparse the string version in
plugin init.

This is unsupported because apollo_rs is not 1.0 and may change before
1.0.

We WILL be changing the way we provide access to the parsed schema.

Use at your own risk.

<!-- start metadata -->
---

**Checklist**

Complete the checklist (and note appropriate exceptions) before the PR
is marked ready-for-review.

- [ ] Changes are compatible[^1]
- [ ] Documentation[^2] completed
- [ ] Performance impact assessed and acceptable
- Tests added and passing[^3]
    - [ ] Unit Tests
    - [ ] Integration Tests
    - [ ] Manual Tests

**Exceptions**

*Note any exceptions here*

**Notes**

[^1]: It may be appropriate to bring upcoming changes to the attention
of other (impacted) groups. Please endeavour to do this before seeking
PR approval. The mechanism for doing this will vary considerably, so use
your judgement as to how and when to do this.
[^2]: Configuration is an important part of many changes. Where
applicable please try to document configuration examples.
[^3]: Tick whichever testing boxes are applicable. If you are adding
Manual Tests, please document the manual testing (extensively) in the
Exceptions.

Co-authored-by: bryn <bryn@apollographql.com>
  • Loading branch information
BrynCooke and bryn committed Mar 26, 2024
1 parent 3308b97 commit 0342fe8
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 37 deletions.
72 changes: 68 additions & 4 deletions apollo-router/src/plugin/mod.rs
Expand Up @@ -19,6 +19,7 @@ pub mod test;

use std::any::TypeId;
use std::fmt;
use std::path::PathBuf;
use std::sync::Arc;
use std::task::Context;
use std::task::Poll;
Expand Down Expand Up @@ -50,6 +51,7 @@ use crate::ListenAddr;
type InstanceFactory = fn(
&serde_json::Value,
Arc<String>,
Arc<apollo_compiler::validation::Valid<apollo_compiler::Schema>>,
Notify<String, graphql::Response>,
) -> BoxFuture<Result<Box<dyn DynPlugin>, BoxError>>;

Expand All @@ -66,6 +68,9 @@ pub struct PluginInit<T> {
pub config: T,
/// Router Supergraph Schema (schema definition language)
pub supergraph_sdl: Arc<String>,
/// The supergraph schema (parsed)
pub(crate) supergraph_schema:
Arc<apollo_compiler::validation::Valid<apollo_compiler::schema::Schema>>,

pub(crate) notify: Notify<String, graphql::Response>,
}
Expand All @@ -79,6 +84,13 @@ where
pub fn new(config: T, supergraph_sdl: Arc<String>) -> Self {
Self::builder()
.config(config)
.supergraph_schema(Arc::new(
apollo_compiler::schema::Schema::parse_and_validate(
supergraph_sdl.to_string(),
PathBuf::from("synthetic"),
)
.expect("failed to parse supergraph schema"),
))
.supergraph_sdl(supergraph_sdl)
.notify(Notify::builder().build())
.build()
Expand All @@ -95,19 +107,48 @@ where
) -> Result<Self, BoxError> {
Self::try_builder()
.config(config)
.supergraph_schema(Arc::new(
apollo_compiler::Schema::parse_and_validate(
supergraph_sdl.to_string(),
PathBuf::from("synthetic"),
)
.map_err(|e| {
// This method is deprecated so we're not going to do anything fancy with the error
BoxError::from(e.errors.to_string())
})?,
))
.supergraph_sdl(supergraph_sdl)
.notify(Notify::builder().build())
.build()
}

#[cfg(test)]
pub(crate) fn fake_new(config: T, supergraph_sdl: Arc<String>) -> Self {
let supergraph_schema = Arc::new(if !supergraph_sdl.is_empty() {
apollo_compiler::Schema::parse_and_validate(
supergraph_sdl.to_string(),
PathBuf::from("synthetic"),
)
.expect("failed to parse supergraph schema")
} else {
apollo_compiler::validation::Valid::assume_valid(apollo_compiler::Schema::new())
});
PluginInit {
config,
supergraph_schema,
supergraph_sdl,
notify: Notify::for_tests(),
}
}

/// Returns the parsed Schema. This is unstable and may be changed or removed in future router releases.
/// In addition, Schema is not stable, and may be changed or removed in future apollo-rs releases.
#[doc(hidden)]
pub fn unsupported_supergraph_schema(
&self,
) -> Arc<apollo_compiler::validation::Valid<apollo_compiler::Schema>> {
self.supergraph_schema.clone()
}
}

#[buildstructor::buildstructor]
Expand All @@ -123,11 +164,13 @@ where
pub(crate) fn new_builder(
config: T,
supergraph_sdl: Arc<String>,
supergraph_schema: Arc<apollo_compiler::validation::Valid<apollo_compiler::schema::Schema>>,
notify: Notify<String, graphql::Response>,
) -> Self {
PluginInit {
config,
supergraph_sdl,
supergraph_schema,
notify,
}
}
Expand All @@ -140,12 +183,14 @@ where
pub(crate) fn try_new_builder(
config: serde_json::Value,
supergraph_sdl: Arc<String>,
supergraph_schema: Arc<apollo_compiler::validation::Valid<apollo_compiler::schema::Schema>>,
notify: Notify<String, graphql::Response>,
) -> Result<Self, BoxError> {
let config: T = serde_json::from_value(config)?;
Ok(PluginInit {
config,
supergraph_sdl,
supergraph_schema,
notify,
})
}
Expand All @@ -155,11 +200,19 @@ where
fn fake_new_builder(
config: T,
supergraph_sdl: Option<Arc<String>>,
supergraph_schema: Option<
Arc<apollo_compiler::validation::Valid<apollo_compiler::schema::Schema>>,
>,
notify: Option<Notify<String, graphql::Response>>,
) -> Self {
PluginInit {
config,
supergraph_sdl: supergraph_sdl.unwrap_or_default(),
supergraph_schema: supergraph_schema.unwrap_or_else(|| {
Arc::new(apollo_compiler::validation::Valid::assume_valid(
apollo_compiler::Schema::new(),
))
}),
notify: notify.unwrap_or_else(Notify::for_tests),
}
}
Expand Down Expand Up @@ -198,11 +251,12 @@ impl PluginFactory {
tracing::debug!(%plugin_factory_name, "creating plugin factory");
PluginFactory {
name: plugin_factory_name,
instance_factory: |configuration, schema, notify| {
instance_factory: |configuration, schema, supergraph_schema, notify| {
Box::pin(async move {
let init = PluginInit::try_builder()
.config(configuration.clone())
.supergraph_sdl(schema)
.supergraph_schema(supergraph_schema)
.notify(notify)
.build()?;
let plugin = P::new(init).await?;
Expand All @@ -225,11 +279,12 @@ impl PluginFactory {
tracing::debug!(%plugin_factory_name, "creating plugin factory");
PluginFactory {
name: plugin_factory_name,
instance_factory: |configuration, schema, notify| {
instance_factory: |configuration, schema, supergraph_schema, notify| {
Box::pin(async move {
let init = PluginInit::try_builder()
.config(configuration.clone())
.supergraph_sdl(schema)
.supergraph_schema(supergraph_schema)
.notify(notify)
.build()?;
let plugin = P::new(init).await?;
Expand All @@ -245,17 +300,26 @@ impl PluginFactory {
&self,
configuration: &serde_json::Value,
supergraph_sdl: Arc<String>,
supergraph_schema: Arc<apollo_compiler::validation::Valid<apollo_compiler::Schema>>,
notify: Notify<String, graphql::Response>,
) -> Result<Box<dyn DynPlugin>, BoxError> {
(self.instance_factory)(configuration, supergraph_sdl, notify).await
(self.instance_factory)(configuration, supergraph_sdl, supergraph_schema, notify).await
}

#[cfg(test)]
pub(crate) async fn create_instance_without_schema(
&self,
configuration: &serde_json::Value,
) -> Result<Box<dyn DynPlugin>, BoxError> {
(self.instance_factory)(configuration, Default::default(), Default::default()).await
(self.instance_factory)(
configuration,
Default::default(),
Arc::new(apollo_compiler::validation::Valid::assume_valid(
apollo_compiler::Schema::new(),
)),
Default::default(),
)
.await
}

pub(crate) fn create_schema(&self, gen: &mut SchemaGenerator) -> schemars::schema::Schema {
Expand Down
4 changes: 1 addition & 3 deletions apollo-router/src/plugins/override_url.rs
Expand Up @@ -113,16 +113,14 @@ mod tests {
let dyn_plugin: Box<dyn DynPlugin> = crate::plugin::plugins()
.find(|factory| factory.name == "apollo.override_subgraph_url")
.expect("Plugin not found")
.create_instance(
.create_instance_without_schema(
&Value::from_str(
r#"{
"test_one": "http://localhost:8001",
"test_two": "http://localhost:8002"
}"#,
)
.unwrap(),
Default::default(),
Default::default(),
)
.await
.unwrap();
Expand Down
14 changes: 11 additions & 3 deletions apollo-router/src/plugins/subscription.rs
Expand Up @@ -681,6 +681,7 @@ fn ensure_id_consistency(
#[cfg(test)]
mod tests {
use std::str::FromStr;
use std::sync::Arc;

use futures::StreamExt;
use serde_json::Value;
Expand Down Expand Up @@ -718,6 +719,9 @@ mod tests {
)
.unwrap(),
Default::default(),
Arc::new(apollo_compiler::validation::Valid::assume_valid(
apollo_compiler::Schema::new(),
)),
notify.clone(),
)
.await
Expand Down Expand Up @@ -856,6 +860,9 @@ mod tests {
)
.unwrap(),
Default::default(),
Arc::new(apollo_compiler::validation::Valid::assume_valid(
apollo_compiler::Schema::new(),
)),
notify.clone(),
)
.await
Expand Down Expand Up @@ -941,6 +948,9 @@ mod tests {
)
.unwrap(),
Default::default(),
Arc::new(apollo_compiler::validation::Valid::assume_valid(
apollo_compiler::Schema::new(),
)),
notify.clone(),
)
.await
Expand Down Expand Up @@ -1076,15 +1086,13 @@ mod tests {
let dyn_plugin: Box<dyn DynPlugin> = crate::plugin::plugins()
.find(|factory| factory.name == APOLLO_SUBSCRIPTION_PLUGIN)
.expect("Plugin not found")
.create_instance(
.create_instance_without_schema(
&Value::from_str(
r#"{
"enabled": false
}"#,
)
.unwrap(),
Default::default(),
Default::default(),
)
.await
.unwrap();
Expand Down
39 changes: 18 additions & 21 deletions apollo-router/src/plugins/telemetry/logging/mod.rs
Expand Up @@ -2,7 +2,6 @@
#[cfg(test)]
mod test {
use std::any::TypeId;
use std::sync::Arc;

use tower::BoxError;
use tower::ServiceBuilder;
Expand All @@ -11,8 +10,8 @@ mod test {

use crate::assert_snapshot_subscriber;
use crate::graphql;
use crate::plugin::DynPlugin;
use crate::plugin::Plugin;
use crate::plugin::PluginInit;
use crate::plugins::telemetry::Telemetry;
use crate::services::router;
use crate::services::subgraph;
Expand Down Expand Up @@ -151,39 +150,37 @@ mod test {
// For now let's try and increase the coverage of the telemetry plugin using this and see how it goes.

struct PluginTestHarness<T: Plugin> {
plugin: T,
plugin: Box<dyn DynPlugin>,
phantom: std::marker::PhantomData<T>,
}
#[buildstructor::buildstructor]
impl<T: Plugin> PluginTestHarness<T> {
#[builder]
async fn new(yaml: Option<&'static str>, supergraph: Option<&'static str>) -> Self {
async fn new(yaml: Option<&'static str>) -> Self {
let factory = crate::plugin::plugins()
.find(|factory| factory.type_id == TypeId::of::<T>())
.expect("plugin not registered");
let name = &factory.name.replace("apollo.", "");
let config = yaml
.map(|yaml| serde_yaml::from_str::<serde_yaml::Value>(yaml).unwrap())
.map(|yaml| serde_yaml::from_str::<serde_json::Value>(yaml).unwrap())
.map(|mut config| {
config
.as_mapping_mut()
.as_object_mut()
.expect("invalid yaml")
.remove(&serde_yaml::Value::String(name.to_string()))
.remove(name)
.expect("no config for plugin")
})
.unwrap_or_else(|| serde_yaml::Value::Mapping(Default::default()));

let supergraph_sdl = supergraph
.map(|s| Arc::new(s.to_string()))
.unwrap_or_default();
let plugin = T::new(PluginInit {
config: serde_yaml::from_value(config).expect("config was invalid"),
supergraph_sdl,
notify: Default::default(),
})
.await
.expect("failed to initialize plugin");

Self { plugin }
.unwrap_or_else(|| serde_json::Value::Object(Default::default()));

let plugin = factory
.create_instance_without_schema(&config)
.await
.expect("failed to create plugin");

Self {
plugin,
phantom: Default::default(),
}
}

#[allow(dead_code)]
Expand Down
6 changes: 2 additions & 4 deletions apollo-router/src/plugins/telemetry/mod.rs
Expand Up @@ -1860,7 +1860,7 @@ mod tests {
let mut plugin = crate::plugin::plugins()
.find(|factory| factory.name == "apollo.telemetry")
.expect("Plugin not found")
.create_instance(telemetry_config, Default::default(), Default::default())
.create_instance_without_schema(telemetry_config)
.await
.unwrap();

Expand Down Expand Up @@ -1935,10 +1935,8 @@ mod tests {
crate::plugin::plugins()
.find(|factory| factory.name == "apollo.telemetry")
.expect("Plugin not found")
.create_instance(
.create_instance_without_schema(
&serde_json::json!({"apollo": {"schema_id":"abc"}, "exporters": {"tracing": {}}}),
Default::default(),
Default::default(),
)
.await
.unwrap();
Expand Down

0 comments on commit 0342fe8

Please sign in to comment.