Skip to main content

graphql_tools/validation/rules/
known_fragment_names.rs

1use super::ValidationRule;
2use crate::ast::{OperationVisitor, OperationVisitorContext};
3use crate::static_graphql::query::*;
4use crate::validation::utils::{ValidationError, ValidationErrorContext};
5
6/// Known fragment names
7///
8/// A GraphQL document is only valid if all `...Fragment` fragment spreads refer
9/// to fragments defined in the same document.
10///
11/// See https://spec.graphql.org/draft/#sec-Fragment-spread-target-defined
12pub struct KnownFragmentNames;
13
14impl Default for KnownFragmentNames {
15    fn default() -> Self {
16        Self::new()
17    }
18}
19
20impl KnownFragmentNames {
21    pub fn new() -> Self {
22        KnownFragmentNames
23    }
24}
25
26impl<'doc> OperationVisitor<'doc, ValidationErrorContext> for KnownFragmentNames {
27    fn enter_fragment_spread(
28        &mut self,
29        visitor_context: &mut OperationVisitorContext,
30        user_context: &mut ValidationErrorContext,
31        fragment_spread: &FragmentSpread,
32    ) {
33        if !visitor_context
34            .known_fragments
35            .contains_key(fragment_spread.fragment_name.as_str())
36        {
37            user_context.report_error(ValidationError {
38                error_code: self.error_code(),
39                locations: vec![fragment_spread.position],
40                message: format!("Unknown fragment \"{}\".", fragment_spread.fragment_name),
41            })
42        }
43    }
44}
45
46impl ValidationRule for KnownFragmentNames {
47    fn error_code(&self) -> &'static str {
48        "KnownFragmentNames"
49    }
50
51    fn visitor<'doc>(&self) -> super::ValidationVisitor<'doc> {
52        Box::new(KnownFragmentNames::new())
53    }
54}
55
56#[test]
57fn valid_fragment() {
58    use crate::validation::test_utils::*;
59
60    let mut plan = create_plan_from_rule(Box::new(KnownFragmentNames {}));
61    let errors = test_operation_with_schema(
62        "{
63          human(id: 4) {
64            ...HumanFields1
65            ... on Human {
66              ...HumanFields2
67            }
68            ... {
69              name
70            }
71          }
72        }
73        fragment HumanFields1 on Human {
74          name
75          ...HumanFields3
76        }
77        fragment HumanFields2 on Human {
78          name
79        }
80        fragment HumanFields3 on Human {
81          name
82        }",
83        TEST_SCHEMA,
84        &mut plan,
85    );
86
87    assert_eq!(get_messages(&errors).len(), 0);
88}
89
90#[test]
91fn invalid_fragment() {
92    use crate::validation::test_utils::*;
93
94    let mut plan = create_plan_from_rule(Box::new(KnownFragmentNames {}));
95    let errors = test_operation_with_schema(
96        "{
97          human(id: 4) {
98            ...UnknownFragment1
99            ... on Human {
100              ...UnknownFragment2
101            }
102          }
103        }
104        fragment HumanFields on Human {
105          name
106          ...UnknownFragment3
107        }",
108        TEST_SCHEMA,
109        &mut plan,
110    );
111
112    let messages = get_messages(&errors);
113    assert_eq!(messages.len(), 3);
114    assert_eq!(
115        messages,
116        vec![
117            "Unknown fragment \"UnknownFragment1\".",
118            "Unknown fragment \"UnknownFragment2\".",
119            "Unknown fragment \"UnknownFragment3\".",
120        ]
121    );
122}