forked from apollographql/rover
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update structure of composition::supergraph::config module (apollogra…
…phql#2285) Just moves some files around and tries to group them a bit more logically
- Loading branch information
Showing
24 changed files
with
1,507 additions
and
1,390 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
//! This module errors related to resolving SupergraphConfigs that are also shared across multiple submodules of [`rover::composition::supergraph::config`] | ||
mod subgraph; | ||
pub use subgraph::*; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
use std::path::PathBuf; | ||
|
||
use camino::Utf8PathBuf; | ||
|
||
/// Errors that may occur as a result of resolving subgraphs | ||
#[derive(thiserror::Error, Debug)] | ||
pub enum ResolveSubgraphError { | ||
/// Occurs when the subgraph schema file cannot found relative to the supplied | ||
/// supergraph config file | ||
#[error("Could not find schema file ({path}) relative to ({supergraph_config_path}) for subgraph `{subgraph_name}`")] | ||
FileNotFound { | ||
/// The subgraph name that failed to be resolved | ||
subgraph_name: String, | ||
/// Supplied path to the supergraph config file | ||
supergraph_config_path: Utf8PathBuf, | ||
/// Supplied path to the subgraph schema file | ||
path: PathBuf, | ||
/// The source error | ||
source: std::io::Error, | ||
}, | ||
/// Occurs as a result of an IO error | ||
#[error(transparent)] | ||
Io(#[from] std::io::Error), | ||
/// Occurs as a result of a rover_std::Fs error | ||
#[error(transparent)] | ||
Fs(Box<dyn std::error::Error + Send + Sync>), | ||
/// Occurs when a introspection against a subgraph fails | ||
#[error("Failed to introspect the subgraph {subgraph_name}.")] | ||
IntrospectionError { | ||
/// The subgraph name that failed to be resolved | ||
subgraph_name: String, | ||
/// The source error | ||
source: Box<dyn std::error::Error + Send + Sync>, | ||
}, | ||
/// Occurs when a supplied graph ref cannot be parsed | ||
#[error("Invalid graph ref: {graph_ref}")] | ||
InvalidGraphRef { | ||
/// The supplied graph ref | ||
graph_ref: String, | ||
/// The source error | ||
source: Box<dyn std::error::Error + Send + Sync>, | ||
}, | ||
/// Occurs when fetching a remote subgraph fails | ||
#[error("Failed to fetch the sdl for subgraph `{subgraph_name}` from remote")] | ||
FetchRemoteSdlError { | ||
/// The name of the subgraph that failed to be resolved | ||
subgraph_name: String, | ||
/// The source error | ||
source: Box<dyn std::error::Error + Send + Sync>, | ||
}, | ||
/// Occurs when a supergraph config filepath waqs expected but not found | ||
#[error("Failed to find the supergraph config, which is required when resolving schemas in a file relative to a supergraph config")] | ||
SupergraphConfigMissing, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
//! Provides objects related to fully resolving a supergraph config. | ||
//! | ||
//! Full resolution is the process of taking a subgraph config and producing | ||
//! a SDL string from whatever subgraph source is provided. This is the input that | ||
//! the supergraph binary expects. | ||
mod subgraph; | ||
mod subgraphs; | ||
mod supergraph; | ||
|
||
pub use subgraph::*; | ||
pub use subgraphs::*; | ||
pub use supergraph::*; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
use std::str::FromStr; | ||
|
||
use apollo_federation_types::config::{SchemaSource, SubgraphConfig}; | ||
use apollo_parser::{cst, Parser}; | ||
use buildstructor::buildstructor; | ||
use camino::Utf8PathBuf; | ||
use derive_getters::Getters; | ||
use rover_client::shared::GraphRef; | ||
use rover_std::Fs; | ||
|
||
use crate::{ | ||
composition::supergraph::config::{ | ||
error::ResolveSubgraphError, unresolved::UnresolvedSubgraph, | ||
}, | ||
utils::effect::{fetch_remote_subgraph::FetchRemoteSubgraph, introspect::IntrospectSubgraph}, | ||
}; | ||
|
||
/// Represents a [`SubgraphConfig`] that has been resolved down to an SDL | ||
#[derive(Clone, Debug, Eq, PartialEq, Getters)] | ||
pub struct FullyResolvedSubgraph { | ||
#[getter(skip)] | ||
routing_url: Option<String>, | ||
#[getter(skip)] | ||
schema: String, | ||
is_fed_two: bool, | ||
} | ||
|
||
#[buildstructor] | ||
impl FullyResolvedSubgraph { | ||
/// Hook for [`buildstructor::buildstructor`]'s builder pattern to create a [`FullyResolvedSubgraph`] | ||
#[builder] | ||
pub fn new( | ||
schema: String, | ||
routing_url: Option<String>, | ||
is_fed_two: Option<bool>, | ||
) -> FullyResolvedSubgraph { | ||
FullyResolvedSubgraph { | ||
schema, | ||
routing_url, | ||
is_fed_two: is_fed_two.unwrap_or_default(), | ||
} | ||
} | ||
/// Resolves a [`UnresolvedSubgraph`] to a [`FullyResolvedSubgraph`] | ||
pub async fn resolve( | ||
introspect_subgraph_impl: &impl IntrospectSubgraph, | ||
fetch_remote_subgraph_impl: &impl FetchRemoteSubgraph, | ||
supergraph_config_root: Option<&Utf8PathBuf>, | ||
unresolved_subgraph: UnresolvedSubgraph, | ||
) -> Result<FullyResolvedSubgraph, ResolveSubgraphError> { | ||
match unresolved_subgraph.schema() { | ||
SchemaSource::File { file } => { | ||
let supergraph_config_root = | ||
supergraph_config_root.ok_or(ResolveSubgraphError::SupergraphConfigMissing)?; | ||
let file = unresolved_subgraph.resolve_file_path(supergraph_config_root, file)?; | ||
let schema = | ||
Fs::read_file(&file).map_err(|err| ResolveSubgraphError::Fs(Box::new(err)))?; | ||
let is_fed_two = schema_contains_link_directive(&schema); | ||
Ok(FullyResolvedSubgraph { | ||
routing_url: unresolved_subgraph.routing_url().clone(), | ||
schema, | ||
is_fed_two, | ||
}) | ||
} | ||
SchemaSource::SubgraphIntrospection { | ||
subgraph_url, | ||
introspection_headers, | ||
} => { | ||
let schema = introspect_subgraph_impl | ||
.introspect_subgraph( | ||
subgraph_url.clone(), | ||
introspection_headers.clone().unwrap_or_default(), | ||
) | ||
.await | ||
.map_err(|err| ResolveSubgraphError::IntrospectionError { | ||
subgraph_name: unresolved_subgraph.name().to_string(), | ||
source: Box::new(err), | ||
})?; | ||
let routing_url = unresolved_subgraph | ||
.routing_url() | ||
.clone() | ||
.or_else(|| Some(subgraph_url.to_string())); | ||
let is_fed_two = schema_contains_link_directive(&schema); | ||
Ok(FullyResolvedSubgraph { | ||
routing_url, | ||
schema, | ||
is_fed_two, | ||
}) | ||
} | ||
SchemaSource::Subgraph { | ||
graphref: graph_ref, | ||
subgraph, | ||
} => { | ||
let graph_ref = GraphRef::from_str(graph_ref).map_err(|err| { | ||
ResolveSubgraphError::InvalidGraphRef { | ||
graph_ref: graph_ref.clone(), | ||
source: Box::new(err), | ||
} | ||
})?; | ||
let remote_subgraph = fetch_remote_subgraph_impl | ||
.fetch_remote_subgraph(graph_ref, subgraph.to_string()) | ||
.await | ||
.map_err(|err| ResolveSubgraphError::FetchRemoteSdlError { | ||
subgraph_name: subgraph.to_string(), | ||
source: Box::new(err), | ||
})?; | ||
let schema = remote_subgraph.schema().clone(); | ||
let is_fed_two = schema_contains_link_directive(&schema); | ||
Ok(FullyResolvedSubgraph { | ||
routing_url: unresolved_subgraph | ||
.routing_url() | ||
.clone() | ||
.or(Some(remote_subgraph.routing_url().to_string())), | ||
schema, | ||
is_fed_two, | ||
}) | ||
} | ||
SchemaSource::Sdl { sdl } => { | ||
let is_fed_two = schema_contains_link_directive(sdl); | ||
Ok(FullyResolvedSubgraph { | ||
routing_url: None, | ||
schema: sdl.to_string(), | ||
is_fed_two, | ||
}) | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl From<FullyResolvedSubgraph> for SubgraphConfig { | ||
fn from(value: FullyResolvedSubgraph) -> Self { | ||
SubgraphConfig { | ||
routing_url: value.routing_url, | ||
schema: SchemaSource::Sdl { sdl: value.schema }, | ||
} | ||
} | ||
} | ||
|
||
fn schema_contains_link_directive(sdl: &str) -> bool { | ||
let parser = Parser::new(sdl); | ||
let parsed_ast = parser.parse(); | ||
let doc = parsed_ast.document(); | ||
doc.definitions().any(|definition| { | ||
match definition { | ||
cst::Definition::SchemaExtension(ext) => ext.directives(), | ||
cst::Definition::SchemaDefinition(def) => def.directives(), | ||
_ => None, | ||
} | ||
.map(|d| d.directives()) | ||
.map(|mut directives| { | ||
directives.any(|directive| { | ||
directive | ||
.name() | ||
.map(|name| "link" == name.text()) | ||
.unwrap_or_default() | ||
}) | ||
}) | ||
.unwrap_or_default() | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
use std::collections::BTreeMap; | ||
|
||
use apollo_federation_types::config::{SchemaSource, SubgraphConfig, SupergraphConfig}; | ||
use thiserror::Error; | ||
|
||
/// Error that occurs when a subgraph schema source is invalid | ||
#[derive(Error, Debug)] | ||
#[error("Invalid schema source: {:?}", .schema_source)] | ||
pub struct InvalidSchemaSource { | ||
schema_source: SchemaSource, | ||
} | ||
|
||
/// Object that contains the completed set of subgraphs resolved to their SDLs | ||
#[derive(Clone, Debug, PartialEq, Eq)] | ||
pub struct FullyResolvedSubgraphs { | ||
subgraphs: BTreeMap<String, String>, | ||
} | ||
|
||
impl FullyResolvedSubgraphs { | ||
#[cfg(test)] | ||
pub fn new(subgraphs: BTreeMap<String, String>) -> FullyResolvedSubgraphs { | ||
FullyResolvedSubgraphs { subgraphs } | ||
} | ||
|
||
/// Used to upsert a fully resolved subgraph into this object's definitions | ||
pub fn upsert_subgraph(&mut self, name: String, schema: String) { | ||
self.subgraphs.insert(name, schema); | ||
} | ||
|
||
/// Removes a subgraph from this object's definitions | ||
pub fn remove_subgraph(&mut self, name: &str) { | ||
self.subgraphs.remove(name); | ||
} | ||
} | ||
|
||
impl TryFrom<SupergraphConfig> for FullyResolvedSubgraphs { | ||
type Error = Vec<InvalidSchemaSource>; | ||
fn try_from(value: SupergraphConfig) -> Result<Self, Self::Error> { | ||
let mut errors = Vec::new(); | ||
let mut subgraph_sdls = BTreeMap::new(); | ||
for (name, subgraph_config) in value.into_iter() { | ||
if let SchemaSource::Sdl { sdl } = subgraph_config.schema { | ||
subgraph_sdls.insert(name, sdl); | ||
} else { | ||
errors.push(InvalidSchemaSource { | ||
schema_source: subgraph_config.schema, | ||
}); | ||
} | ||
} | ||
if errors.is_empty() { | ||
Ok(FullyResolvedSubgraphs { | ||
subgraphs: subgraph_sdls, | ||
}) | ||
} else { | ||
Err(errors) | ||
} | ||
} | ||
} | ||
|
||
impl From<FullyResolvedSubgraphs> for SupergraphConfig { | ||
fn from(value: FullyResolvedSubgraphs) -> Self { | ||
let subgraphs = BTreeMap::from_iter(value.subgraphs.into_iter().map(|(name, sdl)| { | ||
( | ||
name, | ||
SubgraphConfig { | ||
routing_url: None, | ||
schema: SchemaSource::Sdl { sdl }, | ||
}, | ||
) | ||
})); | ||
SupergraphConfig::new(subgraphs, None) | ||
} | ||
} |
Oops, something went wrong.