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}