首页 > 解决方案 > 从可转换为多种类型的函数返回值

问题描述

在我的库中,我调用了一个 REST API,因此有一个通用的反序列化功能。Result<T,E>由于整个过程可能会失败,因此该函数返回 a 是正确的。如果该过程成功完成,我将返回另一个Result<T, E>whereOk(T)指示服务器返回 2xx 状态代码并Err(E)指示 4xx 或 5xx 错误。对于 API 可以返回的每个错误(每个请求都有多种可能性),我拥有,或者更确切地说:想要拥有一个包含错误和有关请求的附加信息的结构。现在,我可以返回一个泛型ErrorResponse而不是E,然后让调用者通过 `From 转换它,但这意味着我没有使用 Rust 的强类型系统和泛型,所以我宁愿避免这种情况。

我想知道的是:我需要替换什么E才能自动反序列化为正确的错误(基于状态码标头)?我已经尝试过使用impl From<ErrorResponse>,但这似乎不起作用。

我的反序列化函数目前看起来像这样:

pub type DeserializationResult<T> = Result<APIResult<T>, DeserializationError>;
pub type APIResult<T> = Result<DataResponse<T>, ErrorResponse>;
                        // What to change here? -------------^

// I want to get rid of this
#[derive(Debug)]
pub(crate) struct ErrorResponse {
    pub headers: reqwest::header::HeaderMap,
    pub status_code: reqwest::StatusCode,
    pub message: Option<String>,
    // Additional fields removed for brevity
}


#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct ErrorDetails {
    pub id: String,
    pub status: u16,
    pub title: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub detail: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub context: Option<String>,
}

#[derive(Error, Debug)]
pub enum DeserializationError {
   // Errors that can occur during deserialization, e.g. "serde_json::Error"
}

pub async fn deserialize_response<T>(response: Response) -> DeserializationResult<T>
    where T: DeserializeOwned,
{
    let status_code = response.status();
    let headers = response.headers().clone();
    let content = response.text().await?;

    if !status_code.is_client_error() && !status_code.is_server_error() {
        let success_result: T = serde_json::from_str(&content)?;
        let data_response = DataResponse {
            status_code,
            headers,
            content: success_result,
        };
        let inner_data = Ok(data_response);
        Ok(inner_data)
    } else {
        let error_result = serde_json::from_str(&content)?;

        let s = StatusCode::from_u16(error_result.status).map_err(|_| DeserializationError::InvalidError)?;
        let error_response = ErrorResponse {
            headers,
            status_code,
            message: error_result.detail.clone(),
        };

        let inner_error = Err(error_response);
        Ok(inner_error)
    }
}

我想这样调用函数:

let de = deserialization::deserialize_response(server_response).await?;
    match de {
        Ok(data_response) => {
            // Some additional conversion steps
            Ok(data)
        }
        Err(e)=> {
            match e.status_code.as_u16() {
                // Currently the error is manually converted here                
            }
        }
    }

我想要的甚至是可能的,还是我需要像现在一样手动转换错误?

标签: genericsrust

解决方案


推荐阅读