graphql_tools/validation/rules/
known_fragment_names.rs

1use super::ValidationRule;
2use crate::ast::{visit_document, 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<'a> OperationVisitor<'a, 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<'a>(&self) -> &'a str {
48        "KnownFragmentNames"
49    }
50
51    fn validate(
52        &self,
53        ctx: &mut OperationVisitorContext,
54        error_collector: &mut ValidationErrorContext,
55    ) {
56        visit_document(
57            &mut KnownFragmentNames::new(),
58            ctx.operation,
59            ctx,
60            error_collector,
61        );
62    }
63}
64
65#[test]
66fn valid_fragment() {
67    use crate::validation::test_utils::*;
68
69    let mut plan = create_plan_from_rule(Box::new(KnownFragmentNames {}));
70    let errors = test_operation_with_schema(
71        "{
72          human(id: 4) {
73            ...HumanFields1
74            ... on Human {
75              ...HumanFields2
76            }
77            ... {
78              name
79            }
80          }
81        }
82        fragment HumanFields1 on Human {
83          name
84          ...HumanFields3
85        }
86        fragment HumanFields2 on Human {
87          name
88        }
89        fragment HumanFields3 on Human {
90          name
91        }",
92        TEST_SCHEMA,
93        &mut plan,
94    );
95
96    assert_eq!(get_messages(&errors).len(), 0);
97}
98
99#[test]
100fn invalid_fragment() {
101    use crate::validation::test_utils::*;
102
103    let mut plan = create_plan_from_rule(Box::new(KnownFragmentNames {}));
104    let errors = test_operation_with_schema(
105        "{
106          human(id: 4) {
107            ...UnknownFragment1
108            ... on Human {
109              ...UnknownFragment2
110            }
111          }
112        }
113        fragment HumanFields on Human {
114          name
115          ...UnknownFragment3
116        }",
117        TEST_SCHEMA,
118        &mut plan,
119    );
120
121    let messages = get_messages(&errors);
122    assert_eq!(messages.len(), 3);
123    assert_eq!(
124        messages,
125        vec![
126            "Unknown fragment \"UnknownFragment1\".",
127            "Unknown fragment \"UnknownFragment2\".",
128            "Unknown fragment \"UnknownFragment3\".",
129        ]
130    );
131}