Rust gql_client请求GraphQL端点时提示缺失data字段解析失败
问题描述
尝试使用如下Rust代码解析GraphQL端点返回的响应:
extern crate serde_derive; use gql_client::Client; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] pub struct DevActivity { pub data: Data, } #[derive(Debug, Serialize, Deserialize)] pub struct Data { #[serde(rename = "getMetric")] pub get_metric: GetMetric, } #[derive(Debug, Serialize, Deserialize)] pub struct GetMetric { #[serde(rename = "timeseriesData")] pub timeseries_data: Vec<TimeseriesDatum>, } #[derive(Debug, Serialize, Deserialize)] pub struct TimeseriesDatum { pub datetime: String, pub value: i64, } #[derive(Serialize)] pub struct Vars { metric: String, } #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { let query = r#" { getMetric(metric: "dev_activity") { timeseriesData(slug: "ethereum", from: "2020-02-10T07:00:00Z", to: "2020-03-10T07:00:00Z", interval: "1w") { datetime value } } } "#; let endpoint = "https://api.santiment.net/graphql"; let client = Client::new(endpoint); let response = client.query::<DevActivity>(query).await.unwrap().unwrap(); for data in &response.data.get_metric.timeseries_data { println!("datetime {}, value {}", data.datetime, data.value) } Ok(()) }
运行代码时触发如下panic报错:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: GQLClient Error: Failed to parse response: Error("missing field `data`", line: 1, column: 294). The response body is: {"data":{"getMetric":{"timeseriesData":[{"datetime":"2020-02-06T00:00:00Z","value":795.0},{"datetime":"2020-02-13T00:00:00Z","value":1281.0},{"datetime":"2020-02-20T00:00:00Z","value":1115.0},{"datetime":"2020-02-27T00:00:00Z","value":952.0},{"datetime":"2020-03-05T00:00:00Z","value":605.0}]}}} ', src/main.rs:49:61
用于接收响应的DevActivity结构体中已经明确定义了data字段,仍无法定位错误产生原因。
错误根因
报错由两处代码问题共同导致:
gql_client库的query方法内置了响应拆包逻辑:库内部定义的通用响应结构已经包含最外层的data字段,调用时传入的泛型类型,会直接匹配data字段对应的JSON对象进行反序列化。当前传入的泛型是DevActivity,该结构要求存在data字段,但库传入反序列化层的对象是{"getMetric": {...}},本身没有data字段,因此触发missing field data错误。- 接口返回的
value字段为浮点数格式(如返回值中的795.0、1281.0),但TimeseriesDatum结构体中value被定义为i64整数类型,即使修复外层结构问题,这里也会因类型不匹配导致反序列化失败。
修复方案
- 删除多余的外层
DevActivity包装结构体,直接将Data结构体作为query方法的泛型参数,匹配库的拆包逻辑。 - 将
TimeseriesDatum中的value字段类型从i64修改为f64,适配接口返回的数值格式。
修复后的核心代码如下:
// 移除原有的DevActivity结构体,无需额外包装外层data字段 #[derive(Debug, Serialize, Deserialize)] pub struct Data { #[serde(rename = "getMetric")] pub get_metric: GetMetric, } #[derive(Debug, Serialize, Deserialize)] pub struct GetMetric { #[serde(rename = "timeseriesData")] pub timeseries_data: Vec<TimeseriesDatum>, } #[derive(Debug, Serialize, Deserialize)] pub struct TimeseriesDatum { pub datetime: String, pub value: f64, // 类型修改为f64匹配浮点数返回 } #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { // 省略query、client初始化部分代码 // 泛型参数改为Data,调整遍历逻辑 let response = client.query::<Data>(query).await.unwrap().unwrap(); for data in &response.get_metric.timeseries_data { println!("datetime {}, value {}", data.datetime, data.value) } Ok(()) }
内容的提问来源于stack exchange,提问作者0xsegfault
相关产品推荐
相关产品推荐

