在Rust中安全高效地处理JSON Web服务响应

oknwwptz  于 2023-03-18  发布在  其他
关注(0)|答案(1)|浏览(130)

我已经搜索了很多,但到目前为止还没有找到我所希望的解决方案:
问:在rust中,什么是正确有效的方法来处理来自一个web服务的json响应,而根据定义,这个响应不是100%可信或依赖的?

  1. json字段/结构是已知的。
    1.值可以为空(或包含意外内容)
    1.处理应该是优雅和健壮的,即,原谅空值/意外值并继续。
    serde将字符串直接解析为let p: Person = serde_json::from_str(data)?;这样的对象的优雅方式似乎不是一种选择,因为如果一个值不符合预期,它就会不优雅地失败。或者,是否有一种选择可以使它更健壮/优雅?
    另一方面,使用let v: Value = serde_json::from_str(data)?;x = v["text"].to_string()提取和验证每个值,并单独捕获每个错误,这不是一个非常有效的解决方案。
    有没有更好的方法来高效地、优雅地、健壮地完成这一任务,至少在值缺失时可以继续,并且可以优雅地处理空值或其他小问题?
    PS:https://docs.rs/serde_json/latest/serde_json/中的示例
rryofs0p

rryofs0p1#

你不能让反序列化既失败又不失败。你需要选择一个或另一个。如果API有时返回“意外内容”,那么这种内容是有效模式的一部分,你可以使用例如无标记枚举来表示它。
例如,如果一个字段 * 通常 * 是一个数字,但有时是一个非数字字符串,或者被完全省略,该怎么办?

#[derive(Deserialize)]
#[serde(untagged)]
enum NumberOrString {
    Number(f64),
    String(String),
}

#[derive(Deserialize)]
struct ApiResponse {
    pub some_value: Option<NumberOrString>,
}

现在,您可以处理以下三种情况中的任何一种:

match response.some_value {
    None => { /* Value was null or missing */ }
    Some(NumberOrString::Number(n)) => { /* Value was numeric */ }
    Some(NumberOrString::String(s)) => { /* Value was a string */ }
}

关键是,如果API有时候用一个与API文档描述的模式相矛盾的结构来响应,那么API文档就是错误的。相反,您应该根据API实际返回的内容来建模您的模式。您可能无法提前知道所有的可能性,因此您的程序有时候会无法反序列化响应。当你了解到一个新的特性时,把它编码到你的程序接受的模式中。Rust的强类型特性,包括它强制match arm是穷举的,意味着当你调整模式时,编译器将指出程序中所有需要修改的地方,以考虑新的可能性。

相关问题