apollo_compiler/
request.rs

1//! GraphQL [requests](https://spec.graphql.org/draft/#request)
2//!
3//! This exists primarily to support [`introspection::partial_execute`].
4
5use crate::executable::Operation;
6use crate::execution::input_coercion::InputCoercionError;
7#[cfg(doc)]
8use crate::introspection;
9use crate::parser::SourceMap;
10use crate::parser::SourceSpan;
11use crate::response::GraphQLError;
12use crate::response::JsonMap;
13use crate::validation::SuspectedValidationBug;
14use crate::validation::Valid;
15use crate::Schema;
16
17/// Coerce the values of [variables](https://spec.graphql.org/draft/#sec-Language.Variables)
18/// from a GraphQL request to the types expected by the operation.
19///
20/// This is [_CoerceVariableValues()_](https://spec.graphql.org/October2021/#CoerceVariableValues())
21/// in the GraphQL specification.
22///
23/// Returns a [request error](https://spec.graphql.org/draft/#sec-Errors.Request-Errors)
24/// if a value as an incompatible type, or if a required variable is not provided.
25pub fn coerce_variable_values(
26    schema: &Valid<Schema>,
27    operation: &Operation,
28    values: &JsonMap,
29) -> Result<Valid<JsonMap>, RequestError> {
30    Ok(crate::execution::input_coercion::coerce_variable_values(
31        schema, operation, values,
32    )?)
33}
34
35/// A [request error](https://spec.graphql.org/draft/#sec-Errors.Request-Errors) is an error
36/// raised during an early phase of the [execution](https://spec.graphql.org/draft/#sec-Execution)
37/// to indicate that the request as a whole is considered faulty.
38///
39/// A request error should cause the rest of execution to be aborted,
40/// and result in a GraphQL response that does not have a `data` key.
41/// This differs from a response with `"data": null` which can happen with
42/// a [field error](https://spec.graphql.org/draft/#sec-Errors.Field-Errors)
43/// on a non-null field whose ancestors fields are all also non-null.
44/// In that case the `null` value
45/// is [propagated](https://spec.graphql.org/draft/#sec-Handling-Field-Errors)
46/// all the way to the entire response data.
47#[derive(Debug, Clone)]
48pub struct RequestError {
49    pub(crate) message: String,
50    pub(crate) location: Option<SourceSpan>,
51    pub(crate) is_suspected_validation_bug: bool,
52}
53
54impl From<InputCoercionError> for RequestError {
55    fn from(error: InputCoercionError) -> Self {
56        match error {
57            InputCoercionError::SuspectedValidationBug(SuspectedValidationBug {
58                message,
59                location,
60            }) => Self {
61                message,
62                location,
63                is_suspected_validation_bug: true,
64            },
65            InputCoercionError::ValueError { message, location } => Self {
66                message,
67                location,
68                is_suspected_validation_bug: false,
69            },
70        }
71    }
72}
73
74impl RequestError {
75    pub fn message(&self) -> impl std::fmt::Display + '_ {
76        &self.message
77    }
78
79    pub fn location(&self) -> Option<SourceSpan> {
80        self.location
81    }
82
83    pub fn to_graphql_error(&self, sources: &SourceMap) -> GraphQLError {
84        let mut error = GraphQLError::new(&self.message, self.location, sources);
85        if self.is_suspected_validation_bug {
86            error
87                .extensions
88                .insert("APOLLO_SUSPECTED_VALIDATION_BUG", true.into());
89        }
90        error
91    }
92}