hive_router_plan_executor/response/
subgraph_response.rs1use core::fmt;
2use std::sync::Arc;
3
4use crate::response::{graphql_error::GraphQLError, value::Value};
5use bytes::Bytes;
6use http::HeaderMap;
7use serde::de::{self, Deserializer, MapAccess, Visitor};
8
9#[derive(Debug, Default)]
10pub struct SubgraphResponse<'a> {
11 pub data: Value<'a>,
12 pub errors: Option<Vec<GraphQLError>>,
13 pub extensions: Option<Value<'a>>,
14 pub headers: Option<Arc<HeaderMap>>,
15 pub bytes: Option<Bytes>,
16}
17
18impl<'de> de::Deserialize<'de> for SubgraphResponse<'de> {
19 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
20 where
21 D: Deserializer<'de>,
22 {
23 struct SubgraphResponseVisitor<'de> {
24 _marker: std::marker::PhantomData<&'de ()>,
25 }
26
27 impl<'de> Visitor<'de> for SubgraphResponseVisitor<'de> {
28 type Value = SubgraphResponse<'de>;
29
30 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
31 formatter
32 .write_str("a GraphQL response object with data, errors, and extensions fields")
33 }
34
35 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
36 where
37 A: MapAccess<'de>,
38 {
39 let mut data = None;
40 let mut errors = None;
41 let mut extensions = None;
42
43 while let Some(key) = map.next_key::<&str>()? {
44 match key {
45 "data" => {
46 if data.is_some() {
47 return Err(de::Error::duplicate_field("data"));
48 }
49 data = Some(map.next_value()?);
51 }
52 "errors" => {
53 if errors.is_some() {
54 return Err(de::Error::duplicate_field("errors"));
55 }
56 errors = Some(map.next_value()?);
58 }
59 "extensions" => {
60 if extensions.is_some() {
61 return Err(de::Error::duplicate_field("extensions"));
62 }
63 extensions = Some(map.next_value()?);
65 }
66 _ => {
67 let _ = map.next_value::<de::IgnoredAny>()?;
69 }
70 }
71 }
72
73 let data = data.unwrap_or(Value::Null);
75
76 Ok(SubgraphResponse {
77 data,
78 errors,
79 extensions,
80 headers: None,
81 bytes: None,
82 })
83 }
84 }
85
86 deserializer.deserialize_map(SubgraphResponseVisitor {
87 _marker: std::marker::PhantomData,
88 })
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 #[test]
96 fn deserialize_response_without_data_with_errors_with_extensions() {
97 let json_response = r#"
98 {
99 "errors": [
100 {
101 "message": "Random error from subgraph",
102 "extensions":{
103 "statusCode": 400
104 }
105 }
106 ]
107 }"#;
108
109 let response: super::SubgraphResponse =
110 sonic_rs::from_str(json_response).expect("Failed to deserialize");
111
112 assert!(response.data.is_null());
113 let errors = response.errors.as_ref().unwrap();
114 insta::assert_snapshot!(sonic_rs::to_string_pretty(&errors).unwrap(), @r###"
115 [
116 {
117 "message": "Random error from subgraph",
118 "extensions": {
119 "statusCode": 400
120 }
121 }
122 ]"###);
123 }
124}