1

我正在使用 rust + Rocket + 柴油 (orm) + serde_derive 来制作一个休息 api。目前,如果柴油由于某种原因未能插入用户,我正在处理 api 的错误处理。它看起来像这样:

pub fn create(user: InsertableUser, connection: &MysqlConnection) -> ApiResponse {
    let result = diesel::insert_into(users::table)
        .values(&InsertableUser::hashed_user(user))
        .execute(connection);
    match result {
        Ok(_) => ApiResponse {
            json: json!({"success": true, "error": null}),
            status: Status::Ok,
        },
        Err(error) => {
            println!("Cannot create the recipe: {:?}", error);
            ApiResponse {
                json: json!({"success": false, "error": error}),
                status: Status::UnprocessableEntity,
            }
        }
    }
}

但是,json: json!({"success": false, "error": error}),给了我这个错误:

the trait bound `diesel::result::Error: user::_IMPL_DESERIALIZE_FOR_User::_serde::Serialize` is not satisfied

the trait `user::_IMPL_DESERIALIZE_FOR_User::_serde::Serialize` is not implemented for `diesel::result::Error`

note: required because of the requirements on the impl of `user::_IMPL_DESERIALIZE_FOR_User::_serde::Serialize` for `&diesel::result::Error`
note: required by `serde_json::value::to_value`rustc(E0277)
<::serde_json::macros::json_internal macros>(123, 27): the trait `user::_IMPL_DESERIALIZE_FOR_User::_serde::Serialize` is not implemented for `diesel::result::Error`

听上去,diesel::result::Errordoes not #[derive(Serialize)],所以不能用json!宏序列化。因此,我需要一些方法来diesel::result::Error实现 implement/derive Serialize

提前感谢您的帮助。

顺便说一句,ApiResponse 看起来像:

use rocket::http::{ContentType, Status};
use rocket::request::Request;
use rocket::response;
use rocket::response::{Responder, Response};
use rocket_contrib::json::JsonValue;

#[derive(Debug)]
pub struct ApiResponse {
    pub json: JsonValue,
    pub status: Status,
}

impl<'r> Responder<'r> for ApiResponse {
    fn respond_to(self, req: &Request) -> response::Result<'r> {
        Response::build_from(self.json.respond_to(&req).unwrap())
            .status(self.status)
            .header(ContentType::JSON)
            .ok()
    }
}
4

2 回答 2

3

Serde 为派生外部 crate 的序列化实现提供了一种解决方法 - 请参阅其文档中的远程 crate 的派生部分。

您必须定义一个与您尝试序列化的枚举具有相同定义的枚举(diesel::result::Error在您的情况下),然后将其标识为您尝试序列化的类型的一种代理,如下所示:

#[derive(Serialize, Deserialize)]
#[serde(remote = "diesel::result::Error")]
struct ErrorDef {
    // Definition in here the same as the enum diesel::result::Error
    // ...
}

当然,您也必须对类型中包含的所有Error类型(或至少任何尚未实现 Serialize 的类型)执行相同的操作。

该文档指出,Serde 会根据“远程”板条箱中的定义检查您提供的定义,如果它们不同,则会引发错误,这将有助于使它们保持同步。

另请注意,这不会导致diesel::result::Error实现 Serialize - 而是您现在有一个替代类型,您可以像这样使用:

struct JsonErrorRespone {
    pub success: bool,
    #[serde(with = "ErrorDef")]
    pub error: diesel::result::Error,
}

然后,您将序列化上述结构的实例,而不是现有的json!宏调用。

或者,上面链接的文档还提供了一些手动调用正确的序列化/反序列化实现的技巧。

免责声明:我还没有使用过这个工具,以上只是从文档中收集的。

于 2019-09-18T01:49:01.967 回答
1

简短的回答:是的,你可以。就个人而言,我一直觉得这有点困难。

作为妥协,您可以只提取与您相关的错误部分,甚至可以这样做:

ApiResponse {
    json: json!({"success": false, "error": error.to_string() }),
    status: Status::UnprocessableEntity,
}

如果您只满足于错误的文本表示。

于 2019-09-18T05:36:34.950 回答