Самый «ржавый» способ обернуть ответы Растсона и избежать дублирования черт? - PullRequest
0 голосов
/ 29 сентября 2018

Я изучаю Rust, но я не уверен в самом элегантном или «ржавом» способе выполнения некоторых действий:

Я извлекаю данные из API, который на некоторых конечных точках возвращаетОбъект JSON ({ value: "resource A" }), но в других случаях он возвращает объект JSON, обернутый другим объектом ({ error: false, data: { value: "resource A" } }).

Я использую Restson для извлечения этих данных.

Мой вопрос: какой самый элегантный способ справиться с разными ответами?Я не знаю, как использовать какой-то абстрактный Response, который мог бы принимать оба вида ответов JSON.

Я имею в виду, в этом случае я реализую 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
    }
}

1 Ответ

0 голосов
/ 29 сентября 2018

У вас есть ответ с двумя вариантами, поэтому можно рассмотреть решение на основе enum:

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

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

Я использовал аннотацию без тега для соответствия формату json:

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

Тогда ваш RestPath импл уменьшится до:

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))
    }
}
...