rust: получить данные json с сайта
Условный сайт site.com отдаёт данные в json, например, такие:
{
"a": {
"text": ["abc", "xyz", "rty", "io", "f"],
"data": [
[null, "txt", 18.1234, 12345678912345, -0.3]
]
},
"b": {
"text": ["qwe", "rty", "asd"],
"data": [
[11343, 0, 20230407131355]
]
}
}
хочу их получить, чтобы потом сохранить в базе postgresql одной записью в формате json.
Пробую http-client reqwest и по ходу потребовался serde:
[dependencies]
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0.159", features = ["derive"] }
serde_json = "1.0"
main.rs:
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Msg {
a: A,
b: B,
}
#[derive(Serialize, Deserialize, Debug)]
struct A {
text: Vec<String>,
data: Vec<Vec<Option<Datum>>>,
}
#[derive(Serialize, Deserialize, Debug)]
struct B {
text: Vec<String>,
data: Vec<Vec<i64>>,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(untagged)]
enum Datum {
Double(f64),
String(String),
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// ...
let resp = reqwest::get("https://site.com")
.await?.json::<Msg>().await?;
// ...
println!("{:?}", resp);
Ok(())
}
println! выводит не то, как ожидаю, а типа такого:
Msg { a: A { text: ["abc", "xyz", ...
data: [[None, Some(String("txt")), Some(Double(18.1234), Some(Double(12345678912345.0)), Some(Double(-0.3))]]
надо так:
Msg { "a": { "text": ["abc", "xyz", ...
"data": [[null, "txt", 18.1234, 12345678912345, -0.3]]
а лучше без Msg, чтоб как оригинал:
{
"a": {
"text": ["abc", "xyz", "rty", "io", "f"],
"data": [
[null, "txt", 18.1234, 12345678912345, -0.3]
]
},
"b": {
"text": ["qwe", "rty", "asd"],
"data": [
[11343, 0, 20230407131355]
]
}
}
Как получить правильно, чтобы a и text в кавычках, без A без Some(String ... Double и целыми числами?
Ответы (1 шт):
Как ни странно, json::<Msg>().await означает: "Десериализуй из JSON в объект типа Msg". То есть JSON у вас на руках не оказывается, а вместо него - сразу настоящая rust-структура (имплементация трейта Debug {:?} которой не претендует на совместимость с JSON). Потому тут есть два путя:
- Не десериализовывать тело, а вытащить его как текст, получив всамделешний JSON в виде строки:
let resp = reqwest::get("https://site.com").await?
.text().await?;
Потом, когда это будет необходимо, строку можно десериализовать в объект (let msg = serde_json::from_str::<Msg>(&resp)?;)
- Вручную сериализовать
Msgобратно в JSON там, где вам это необходимо:
println!("{}", &serde_json::to_string(&resp)?);