You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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整数类型,即使修复外层结构问题,这里也会因类型不匹配导致反序列化失败。
修复方案
  1. 删除多余的外层DevActivity包装结构体,直接将Data结构体作为query方法的泛型参数,匹配库的拆包逻辑。
  2. 将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 10:15:30