From 0b69c595b6ed097560b48ad6010006deca330282 Mon Sep 17 00:00:00 2001 From: Paolo Barbolini Date: Sat, 2 May 2020 17:32:33 +0200 Subject: [PATCH] Make Response::into_json deserialize into a serde DeserializeOwned This removes the necessity to take the result of Response::into_json and having to convert it into a struct by using serde_json::from_value This adds no new dependencies since serde_json already depends on serde. Users of ureq will have to include `serde_derive` either by importing it directly or by using serde with the `derive` feature, unless they want to manually implement `Deserialize` on their structs. --- Cargo.toml | 6 +++++- src/body.rs | 2 -- src/response.rs | 29 ++++++++++++++++++++--------- src/test/simple.rs | 11 +++++++++-- tests/https-agent.rs | 13 ++++++++++--- 5 files changed, 44 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 81067ee..f04a90c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ all-features = true [features] default = ["tls", "cookies"] -json = ["serde_json"] +json = ["serde", "serde_json"] charset = ["encoding"] tls = ["rustls", "webpki", "webpki-roots"] native-certs = ["rustls-native-certs"] @@ -34,5 +34,9 @@ rustls = { version = "0.17", optional = true, features = [] } webpki = { version = "0.21", optional = true } webpki-roots = { version = "0.19", optional = true } rustls-native-certs = { version = "0.3", optional = true } +serde = { version = "1", optional = true } serde_json = { version = "1", optional = true } encoding = { version = "0.2", optional = true } + +[dev-dependencies] +serde = { version = "1", features = ["derive"] } diff --git a/src/body.rs b/src/body.rs index bbc2810..998da35 100644 --- a/src/body.rs +++ b/src/body.rs @@ -10,8 +10,6 @@ use encoding::EncoderTrap; #[cfg(feature = "json")] use super::SerdeValue; -#[cfg(feature = "json")] -use serde_json; /// The different kinds of bodies to send. /// diff --git a/src/response.rs b/src/response.rs index 0a6ede7..4afcc63 100644 --- a/src/response.rs +++ b/src/response.rs @@ -10,7 +10,7 @@ use crate::stream::Stream; use crate::unit::Unit; #[cfg(feature = "json")] -use serde_json; +use serde::de::DeserializeOwned; #[cfg(feature = "charset")] use encoding::label::encoding_from_whatwg_label; @@ -382,16 +382,23 @@ impl Response { /// Example: /// /// ``` + /// # use serde::Deserialize; + /// + /// #[derive(Deserialize)] + /// struct Hello { + /// hello: String, + /// } + /// /// let resp = /// ureq::get("https://ureq.s3.eu-central-1.amazonaws.com/hello_world.json") /// .call(); /// - /// let json = resp.into_json().unwrap(); + /// let json = resp.into_json::().unwrap(); /// - /// assert_eq!(json["hello"], "world"); + /// assert_eq!(json.hello, "world"); /// ``` #[cfg(feature = "json")] - pub fn into_json(self) -> IoResult { + pub fn into_json(self) -> IoResult { let reader = self.into_reader(); serde_json::from_reader(reader).map_err(|e| { IoError::new( @@ -723,15 +730,19 @@ mod tests { #[test] #[cfg(feature = "json")] fn parse_simple_json() { + use serde::Deserialize; + + #[derive(Deserialize)] + struct Hello { + hello: String, + } + let s = "HTTP/1.1 200 OK\r\n\ \r\n\ {\"hello\":\"world\"}"; let resp = s.parse::().unwrap(); - let v = resp.into_json().unwrap(); - let compare = "{\"hello\":\"world\"}" - .parse::() - .unwrap(); - assert_eq!(v, compare); + let v = resp.into_json::().unwrap(); + assert_eq!(v.hello, "world"); } #[test] diff --git a/src/test/simple.rs b/src/test/simple.rs index e596057..aff836b 100644 --- a/src/test/simple.rs +++ b/src/test/simple.rs @@ -61,6 +61,13 @@ fn body_as_text() { #[test] #[cfg(feature = "json")] fn body_as_json() { + use serde::Deserialize; + + #[derive(Deserialize)] + struct Hello { + hello: String, + } + test::set_handler("/body_as_json", |_unit| { test::make_response( 200, @@ -70,8 +77,8 @@ fn body_as_json() { ) }); let resp = get("test://host/body_as_json").call(); - let json = resp.into_json().unwrap(); - assert_eq!(json["hello"], "world"); + let json = resp.into_json::().unwrap(); + assert_eq!(json.hello, "world"); } #[test] diff --git a/tests/https-agent.rs b/tests/https-agent.rs index 075d8be..0e65a77 100644 --- a/tests/https-agent.rs +++ b/tests/https-agent.rs @@ -17,6 +17,14 @@ fn tls_connection_close() { #[cfg(feature = "json")] #[test] fn agent_set_cookie() { + use serde::Deserialize; + use std::collections::HashMap; + + #[derive(Deserialize)] + struct HttpBin { + headers: HashMap, + } + let agent = ureq::Agent::default().build(); let cookie = ureq::Cookie::build("name", "value") .domain("httpbin.org") @@ -30,10 +38,9 @@ fn agent_set_cookie() { assert_eq!(resp.status(), 200); assert_eq!( "name=value", - resp.into_json() - .unwrap() - .get("headers") + resp.into_json::() .unwrap() + .headers .get("Cookie") .unwrap() );