大多数 "rusty" 包装 Rustson 响应并避免重复特征的方法?

Most "rusty" way to wrap Rustson responses and avoid duplicated traits?

我正在学习 Rust,但我不确定最优雅或 "rusty" 做某些事情的方式:

我正在从一个 API 中检索数据,在某些端点上 returns 一个 JSON 对象 ({ value: "resource A" }),但在其他情况下,它 returns 一个 JSON 对象被另一个对象 ({ error: false, data: { value: "resource A" } }) 包裹。

我正在使用 Restson 检索该数据。

我的问题是:处理不同响应的最优雅的方法是什么?我不知道如何使用某种可以接受两种 JSON 响应的抽象 Response

我的意思是,在这种情况下,我实现了 2 个特征,但它们具有相同的内容,所以,对我来说,它闻起来好像那里有问题。

这是一个简化的示例,因此可能存在拼写错误:

use restson::{RestPath, RestClient, Error};

#[derive(Debug, Serialize, Deserialize)]
struct Response<T> {
    error: bool,
    data: T
}

#[derive(Debug, Serialize, Deserialize)]
struct ResourceA {
    value: String,
}

// HERE: How do I remove this duplication?  
impl<'a> RestPath<(&'a str, String)> for ResourceA {
    fn get_path(params: (i8, String, &str)) -> Result<String, Error> {
        let (resource, id) = params;
        Ok(format!("{}/{}", resource, id))
    }
}
impl<'a, T> RestPath<(&'a str, String)> for Response<T> {
    fn get_path(params: (&str, String)) -> Result<String, Error> {
        let (resource, id) = params;
        Ok(format!("{}/{}", resource, id))
    }
}

pub struct Client {
    client: RestClient,
}

impl Client {
    pub fn new() -> Client {
        Client {
            client: RestClient::new("http://my.client").unwrap(),
        }
    }

    pub fn get_resource_a(&mut self, id: String) -> ResourceA {
        let params = ("a", id);
        self.client.get(params).unwrap()
    }

    pub fn get_resource_a2(&mut self, id: String) -> ResourceA {
        let params = ("a2", id);
        let response: Response<ResourceA> = self.api_client.get(params).unwrap();
        response.data
    }
}

您有两个变体的响应,因此可以考虑基于枚举的解决方案:

#[derive(Debug, Serialize, Deserialize)]
struct ResourceA {
    value: String,
}

#[derive(Debug, Serialize, Deserialize]
#[serde(untagged)]
pub enum Response {
    ErrAndValue{error: bool, data: ResourceA},
    Simple(ResourceA),
}

我使用了 untagged 注释来符合 json 格式:

{ value: "resource A" }
{ error: false, data: { value: "resource A" } }

然后你的 RestPath impl 减少到:

impl<'a> RestPath<(&'a str, String)> for Response {
    fn get_path(params: (&str, String)) -> Result<String, Error> {
        let (resource, id) = params;
        Ok(format!("{}/{}", resource, id))
    }
}