Обработка ошибок при обработке ржавчины с помощью Reqwest - PullRequest
3 голосов
/ 25 апреля 2020

Я использую ящик reqwest (версия 0.10.4) для HTTP-вызовов в моем приложении Rust, но не могу найти примеров того, как обрабатывать вызовы API, которые могли бы возвращать более одного возможного тела ответа, главным образом для обработки ошибок.

Например, вызов API может отвечать успешной структурой JSON или структурой ошибок в формате:

{
    "errors": ["..."]
}

В настоящее время у меня есть этот код для функции , но не могу понять, как определить, struct, что мне нужно для десериализации буфера ответов, в зависимости от того, был ли успешным HTTP-запрос.

use super::responses::{Error, Response};
use crate::clients::HttpClient;
use crate::errors::HttpError;
use reqwest::header;

pub fn call() -> Result<Response, HttpError> {
    let url = format!("{}/auth/userpass/login/{}", addr, user);
    let response = HttpClient::new()
        .post(&url)
        .header(header::ACCEPT, "application/json")
        .header(header::CONTENT_TYPE, "application/json")
        .json(&serde_json::json!({ "password": pass }))
        .send();

    match response {
        Ok(res) => {
            let payload = res.json(); // could be `Error` or `Response` but only parses to `Response`
            match payload {
                Ok(j) => Ok(j),
                Err(e) => Err(HttpError::JsonParse(e)),
            }
        }
        Err(e) => Err(HttpError::RequestFailed(e)),
    }
}

Я что-то пропустил в документация для reqwest или это распространенная проблема?

1 Ответ

1 голос
/ 25 апреля 2020

Внутренне, res.json() использует ящик serde_json для десериализации из json вашего объекта ржавчины.

В Rust, когда вы хотите, чтобы тип имел несколько различных переменных, вы используете Enum , serde реализует это поведение для вас, что позволяет вам десериализовать в перечисление на основе формата, десериализированного из. Например, вы можете определить свой ответ enum следующим образом:

#[derive(Serialize, Deserialize)]
#[serde(untagged)]
enum ResponseType {
  Ok(/* fields */),
  Err(/* fields */),
}

Там много чего происходит, но вот основные моменты: #[serde(untagged)] говорит serde, что перечисление должно различаться только по полям в Хорошо и ошибаться В вашем коде Rust вы можете дифференцировать с помощью enum variante, используя полный диапазон сопоставления с образцом и т. Д. c.

. Для вашего конкретного c варианта использования, похоже, что перечисление std Result<V, E> должно будь достаточно хорош.

...