How to get serde_with::nested::json dependency imported properly - rust

I'm trying to use the setup as outlined in the serde_with docs here to deserialize nested json into my struct: https://docs.rs/serde_with/1.4.0/serde_with/json/nested/index.html
After a few tries Cargo.toml file looks like:
[dependencies]
serde = { version = "1.0", features = ["derive"] }
//serde_with = { version = "1.4.0", features = ["..."] } // this doesn't work even though that's what the serde_with README calls for
serde_with = { version = "1.4.0", optional = true }
serde_json = "1.0"
Trying the above I get an error such as:
#[serde(default, rename(deserialize = "Plan"), with="serde_with::json::nested")]
^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type or module `serde_with`
What am I doing wrong?

In your example the module serde_with is not optional and must provide the feature json.
Replace
serde_with = { version = "1.4.0", optional = true}
with
serde_with = { version = "1.4.0", features = ["json"]}
Full example:
Cargo.toml
[dependencies]
serde = { version = "1.0" }
serde_json = "1.0"
serde_derive = "1.0"
serde_with = { version = "1.4.0", features = ["json"]}
main.rs
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
#[derive(Deserialize, Serialize)]
struct A {
#[serde(with = "serde_with::json::nested")]
other_struct: B,
}
#[derive(Deserialize, Serialize)]
struct B {
value: usize,
}
fn main() {
let v: A = serde_json::from_str(r#"{"other_struct":"{\"value\":5}"}"#).unwrap();
assert_eq!(5, v.other_struct.value);
let x = A {
other_struct: B { value: 10 },
};
assert_eq!(r#"{"other_struct":"{\"value\":10}"}"#, serde_json::to_string(&x).unwrap());
}

Related

How to use rocket_cors with Rocket 0.5

I want to use the crate rocket_cors for Rocket v0.5.0-rc.2 but it does not compile because "the trait bound 'Cors: Fairing' is not satisfied".
Here is my Cargo.toml:
# --snip--
[dependencies]
rocket = { version = "0.5.0-rc.2", features = [ "json" ] }
rocket_cors = { version = "0.5.2", default-features = false }
# --snip--
And here is my rocket() function:
fn rocket() -> _ {
let cors = rocket_cors::CorsOptions {
allowed_origins: AllowedOrigins::all(),
allowed_headers: AllowedHeaders::some(&["Authorization", "Accept"]),
allow_credentials: true,
..Default::default()
}
.to_cors()
.unwrap();
rocket::build()
.attach(DbConnection::fairing())
.attach(cors) // <- Here's the error: "the trait `Fairing` is not implemented for `Cors`"
.mount("/", routes![get_tasks])
}
I won't have a problem if the solution is using another CORS crate either.

Rust-analyzer web-sys document is "unknown"

Why is the document object unknown. In fact, everything, even the window.document call is not linted. Linting is quite important for me to lean a new programming language/library.
lib.rs
use wasm_bindgen::prelude::*;
#[wasm_bindgen(start)]
pub fn run() -> Result<(), JsValue> {
let window = web_sys::window().expect("could not get window handle");
let document = window.document().expect("could not get document handle");
let body = document.body().expect("could not get body handle");
let val = document.create_element("p")?;
val.set_text_content(Some("Hello from rust"));
body.append_child(&val)?;
Ok(())
}
cargo.toml
[lib]
crate-type = ["cdylib"]
[dependencies]
serde = { version = "1.0", features = ["derive"] }
wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
[dependencies.web-sys]
version = "0.3.53"
features = [
"Document",
"Element",
"HtmlElement",
"Node",
"Window",
]

Unable to serve static files

Since the task is to distribute pictures - I follow the next guide:
https://actix.rs/docs/static-files/
For example, I created a directory (static) in the project and uploaded 1 image to it:
Then I write the following code:
(pay attention only to the lines (there are only two) with comments: // Taken from the guide)
use actix_cors::Cors;
use actix_web::{http, web, get, post, App, HttpResponse, HttpServer, Result};
use serde::{Deserialize, Serialize};
use actix_files::Files; // Taken from the guide
#[derive(Serialize, Deserialize)]
struct MyObj {
name: String,
}
#[derive(Serialize, Deserialize, Clone)]
struct MyParams {
foo: Option<String>,
}
#[derive(Serialize, Deserialize)]
struct MyResponseObj {
name: String,
params: MyParams,
}
#[get("/{name}")]
async fn index_get(path: web::Path<MyObj>, params: web::Query<MyParams>) -> Result<HttpResponse> {
Ok(HttpResponse::Ok().json(MyResponseObj {
name: path.name.to_string(),
params: params.clone(),
}))
}
#[post("/{name}")]
async fn index_post(path: web::Path<MyObj>, params: web::Json<MyParams>) -> Result<HttpResponse> {
hello().await;
println!("{:?}", params.foo);
println!("{:?}", path.name);
Ok(HttpResponse::Ok().json(MyResponseObj {
name: path.name.to_string(),
params: params.clone(),
}))
}
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new()
.wrap(
Cors::new() // <- Construct CORS middleware builder
.allowed_origin("http://localhost:3000")
.allowed_methods(vec!["GET", "POST"])
.allowed_headers(vec![http::header::AUTHORIZATION, http::header::ACCEPT])
.allowed_header(http::header::CONTENT_TYPE)
.max_age(3600)
.finish())
.service(Files::new("/static", ".")) // Taken from the guide
.service(index_get)
.service(index_post)
)
.bind("127.0.0.1:8088")?
.run()
.await
}
Cargo.toml
[package]
name = "hello_world"
version = "0.1.0"
authors = ["Mike_Kharkov <yamaradg#gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
actix-web = "3.0.1"
actix-rt = "1.1.1"
actix-cors = "0.3.0"
actix-files = "0.3.0"
postgres = "0.17.5"
serde = { version = "1.0.116", features = ["derive"] }
serde_json = "1.0"
json = "0.12"
tokio-postgres = "0.5.5"
tokio = "0.2.22"
env_logger = "0.7.1"
Question:
What else needs to be written (and where exactly) so that it becomes possible to refer to the above picture (for example, from localhost) and not get this kind of error?
The problem is solved:
.service(Files::new("/static", std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("static")))

How can I return JSON from a Rust (Rocket) HTTP endpoint?

What is the easiest way to return Json via Rocket in Rust?
#[post("/route", data = "<data>")]
fn route(someVariable: String) -> String {
// How can I return a json response here? {"a": "{someVariable}")
}
I tried: content::Json() but it seemed too static for me.
If you're finding content::Json() too static you can use the rocket_contrib package. Using this package will allow you to pass in a struct that implements Deserialize from the serde package
use rocket_contrib::json::Json;
use serde::Deserialize;
#[derive(Deserialize)]
struct User {
name: String,
age: u8,
alive: bool,
}
#[post("/route", data = "<data>")]
fn route(someVariable: String) -> String {
let user = User {
name: "Jon Snow".to_string(),
age: 21,
alive: true,
};
Json(user_from_id)
}
Make sure you add the dependencies to your Cargo.toml
serde = { version = "1.0", features = ["derive"] }
rocket_contrib = "0.4"
More information on rocket_contrib https://api.rocket.rs/v0.4/rocket_contrib/json/struct.Json.html
Easiest way would be just using serde_json:
serde_json::to_string(&MyStructObject);
serde_json::to_string will return a Result< String > where the string is a json string. Finally in your Cargo.toml you need to have the following:
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

How to convert serde_json::error::Error to reqwest::error::Error?

reqwest v0.9 has serde v1.0 as a dependency and as a result implements converting serde_json errors into reqwest error.
In my code, I am doing some deserialization using serde_json instead of using .json() method that comes with reqwest.
// reqwest = "0.9"
// serde = { version = "1.0", features = ["derive"] }
// serde_json = "1.0"
pub fn get_meta(client: &reqwest::Client) -> Result<Meta, reqwest::Error> {
let mut resp = client
.get("http://localhost:8080/requests/playlist.json")
.send()?;
let data: Value = serde_json::from_str(&resp.text()?).unwrap();
let data = data["children"][0]["children"].clone();
let metas: Vec<Meta> = serde_json::from_value(data).unwrap();
let meta: Meta = metas.last().expect("nothing is playing").clone();
Ok(meta)
}
Currently, I am trying to return serde_json errors as reqwest errors. Changing let metas: Vec<Meta> = serde_json::from_value(data).unwrap(); to let metas: Vec<Meta> = serde_json::from_value(data)?; fails with the following error:
the trait `std::convert::From<serde_json::error::Error>` is not implemented for `reqwest::error::Error`
Is it possible to convert serde_json::error::Error to reqwest::error::Error by wrapping it inside Kind::Json error enum of reqwest, or do I have to make a custom error enum that encompasses both as mentioned in this article?
No, you can't construct reqwest::Error value yourself because it:
has non-public fields
does not expose public constructors
does not have From implementations for public types
Fortunately both reqwest::Error and serde_json::error::Error implement std::error::Error trait. Following the recommendation from the blog post you linked, the anyhow crate is very helpful here:
// reqwest = "0.9"
// serde = { version = "1.0", features = ["derive"] }
// serde_json = "1.0"
// anyhow = "1.0"
pub fn get_meta(client: &reqwest::Client) -> Result<Meta, anyhow::Error> {
let mut resp = client
.get("http://localhost:8080/requests/playlist.json")
.send()?;
let data: Value = serde_json::from_str(&resp.text()?).unwrap();
let data = data["children"][0]["children"].clone();
let metas: Vec<Meta> = serde_json::from_value(data).unwrap();
let meta: Meta = metas.last().expect("nothing is playing").clone();
Ok(meta)
}

Resources