Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

fix(graphql): include introspection fields in error #4968

Merged
merged 4 commits into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions graph/src/schema/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,13 @@ pub use fulltext::{FulltextAlgorithm, FulltextConfig, FulltextDefinition, Fullte
pub use input_schema::InputSchema;

pub const SCHEMA_TYPE_NAME: &str = "_Schema_";
pub const INTROSPECTION_SCHEMA_FIELD_NAME: &str = "__schema";

pub const META_FIELD_TYPE: &str = "_Meta_";
pub const META_FIELD_NAME: &str = "_meta";

pub const INTROSPECTION_TYPE_FIELD_NAME: &str = "__type";

pub const BLOCK_FIELD_TYPE: &str = "_Block_";

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
Expand Down
42 changes: 35 additions & 7 deletions graphql/src/store/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ use graph::data::graphql::{object, ObjectOrInterface};
use graph::data::query::{CacheStatus, Trace};
use graph::data::value::{Object, Word};
use graph::prelude::*;
use graph::schema::{ast as sast, ApiSchema, META_FIELD_TYPE};
use graph::schema::{
ast as sast, ApiSchema, INTROSPECTION_SCHEMA_FIELD_NAME, INTROSPECTION_TYPE_FIELD_NAME,
META_FIELD_NAME, META_FIELD_TYPE,
};
use graph::schema::{ErrorPolicy, BLOCK_FIELD_TYPE};

use crate::execution::{ast as a, Query};
Expand Down Expand Up @@ -382,12 +385,37 @@ impl Resolver for StoreResolver {
// Note that the meta field could have been queried under a different response key,
// or a different field queried under the response key `_meta`.
ErrorPolicy::Deny => {
let data = result.take_data();
let meta =
data.and_then(|mut d| d.remove("_meta").map(|m| ("_meta".to_string(), m)));
result.set_data(
meta.map(|(key, value)| Object::from_iter(Some((Word::from(key), value)))),
);
let mut data = result.take_data();

// Only keep the _meta, __schema and __type fields from the data
let meta_fields = data.as_mut().and_then(|d| {
let meta_field = d.remove(META_FIELD_NAME);
let schema_field = d.remove(INTROSPECTION_SCHEMA_FIELD_NAME);
let type_field = d.remove(INTROSPECTION_TYPE_FIELD_NAME);

// combine the fields into a vector
let mut meta_fields = Vec::new();

if let Some(meta_field) = meta_field {
meta_fields.push((Word::from(META_FIELD_NAME), meta_field));
}
if let Some(schema_field) = schema_field {
meta_fields
.push((Word::from(INTROSPECTION_SCHEMA_FIELD_NAME), schema_field));
}
if let Some(type_field) = type_field {
meta_fields.push((Word::from(INTROSPECTION_TYPE_FIELD_NAME), type_field));
}

// return the object if it is not empty
if meta_fields.is_empty() {
None
} else {
Some(Object::from_iter(meta_fields))
}
});

result.set_data(meta_fields);
}
ErrorPolicy::Allow => (),
}
Expand Down
58 changes: 58 additions & 0 deletions store/test-store/tests/graphql/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2579,6 +2579,45 @@ fn non_fatal_errors() {
});
assert_eq!(expected, serde_json::to_value(&result).unwrap());

// Introspection queries are not affected.
let query =
"query { __schema { queryType { name } } __type(name: \"Musician\") { name } }";
let result = execute_query(&deployment, query).await;
let expected = json!({
"data": {
"__schema": {
"queryType": {
"name": "Query"
}
},
"__type": {
"name": "Musician"
}
},
"errors": [
{
"message": "indexing_error"
}
]
});
assert_eq!(expected, serde_json::to_value(&result).unwrap());

let query = "query { __type(name: \"Musician\") { name } }";
let result = execute_query(&deployment, query).await;
let expected = json!({
"data": {
"__type": {
"name": "Musician"
}
},
"errors": [
{
"message": "indexing_error"
}
]
});
assert_eq!(expected, serde_json::to_value(&result).unwrap());

// With `allow`, the error remains but the data is included.
let query = "query { musician(id: \"m1\", subgraphError: allow) { id } }";
let result = execute_query(&deployment, query).await;
Expand Down Expand Up @@ -2662,6 +2701,25 @@ fn deterministic_error() {
]
});
assert_eq!(expected, serde_json::to_value(&result).unwrap());

// Introspection queries are not affected.
let query = "query { __schema { queryType { name } } }";
let result = execute_query(&deployment, query).await;
let expected = json!({
"data": {
"__schema": {
"queryType": {
"name": "Query"
}
}
},
"errors": [
{
"message": "indexing_error"
}
]
});
assert_eq!(expected, serde_json::to_value(&result).unwrap());
})
}

Expand Down