apollo_federation/composition/
mod.rs1mod satisfiability;
2
3use std::vec;
4
5use tracing::instrument;
6
7pub use crate::composition::satisfiability::validate_satisfiability;
8use crate::error::CompositionError;
9use crate::merger::merge::Merger;
10pub use crate::schema::schema_upgrader::upgrade_subgraphs_if_necessary;
11use crate::schema::validators::root_fields::validate_consistent_root_fields;
12use crate::subgraph::typestate::Expanded;
13use crate::subgraph::typestate::Initial;
14use crate::subgraph::typestate::Subgraph;
15use crate::subgraph::typestate::Validated;
16pub use crate::supergraph::Merged;
17pub use crate::supergraph::Satisfiable;
18pub use crate::supergraph::Supergraph;
19
20#[instrument(skip(subgraphs))]
21pub fn compose(
22 subgraphs: Vec<Subgraph<Initial>>,
23) -> Result<Supergraph<Satisfiable>, Vec<CompositionError>> {
24 tracing::debug!("Expanding subgraphs...");
25 let expanded_subgraphs = expand_subgraphs(subgraphs)?;
26 tracing::debug!("Upgrading subgraphs...");
27 let validated_subgraphs = upgrade_subgraphs_if_necessary(expanded_subgraphs)?;
28
29 tracing::debug!("Pre-merge validations...");
30 pre_merge_validations(&validated_subgraphs)?;
31 tracing::debug!("Merging subgraphs...");
32 let supergraph = merge_subgraphs(validated_subgraphs)?;
33 tracing::debug!("Post-merge validations...");
34 post_merge_validations(&supergraph)?;
35 tracing::debug!("Validating satisfiability...");
36 validate_satisfiability(supergraph)
37}
38
39#[instrument(skip(subgraphs))]
42pub fn expand_subgraphs(
43 subgraphs: Vec<Subgraph<Initial>>,
44) -> Result<Vec<Subgraph<Expanded>>, Vec<CompositionError>> {
45 let mut errors: Vec<CompositionError> = vec![];
46 let expanded: Vec<Subgraph<Expanded>> = subgraphs
47 .into_iter()
48 .map(|s| s.expand_links())
49 .filter_map(|r| r.map_err(|e| errors.extend(e.to_composition_errors())).ok())
50 .collect();
51 if errors.is_empty() {
52 Ok(expanded)
53 } else {
54 Err(errors)
55 }
56}
57
58#[instrument(skip(subgraphs))]
60pub fn pre_merge_validations(
61 subgraphs: &[Subgraph<Validated>],
62) -> Result<(), Vec<CompositionError>> {
63 validate_consistent_root_fields(subgraphs)?;
64 Ok(())
66}
67
68#[instrument(skip(subgraphs))]
69pub fn merge_subgraphs(
70 subgraphs: Vec<Subgraph<Validated>>,
71) -> Result<Supergraph<Merged>, Vec<CompositionError>> {
72 let merger = Merger::new(subgraphs, Default::default()).map_err(|e| {
73 vec![CompositionError::InternalError {
74 message: e.to_string(),
75 }]
76 })?;
77 let result = merger.merge().map_err(|e| {
78 vec![CompositionError::InternalError {
79 message: e.to_string(),
80 }]
81 })?;
82 tracing::trace!(
83 "Merge has {} errors and {} hints",
84 result.errors.len(),
85 result.hints.len()
86 );
87 if result.errors.is_empty() {
88 let Some(supergraph_schema) = result.supergraph else {
89 return Err(vec![CompositionError::InternalError {
90 message: "Merge completed with no supergraph schema".to_string(),
91 }]);
92 };
93 let supergraph = Supergraph::with_hints(supergraph_schema, result.hints);
94 Ok(supergraph)
95 } else {
96 Err(result.errors)
97 }
98}
99
100#[instrument(skip(_supergraph))]
101pub fn post_merge_validations(
102 _supergraph: &Supergraph<Merged>,
103) -> Result<(), Vec<CompositionError>> {
104 Ok(())
107}