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.
This commit is contained in:
committed by
Martin Algesten
parent
8f2d094cef
commit
0b69c595b6
@@ -15,7 +15,7 @@ all-features = true
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["tls", "cookies"]
|
default = ["tls", "cookies"]
|
||||||
json = ["serde_json"]
|
json = ["serde", "serde_json"]
|
||||||
charset = ["encoding"]
|
charset = ["encoding"]
|
||||||
tls = ["rustls", "webpki", "webpki-roots"]
|
tls = ["rustls", "webpki", "webpki-roots"]
|
||||||
native-certs = ["rustls-native-certs"]
|
native-certs = ["rustls-native-certs"]
|
||||||
@@ -34,5 +34,9 @@ rustls = { version = "0.17", optional = true, features = [] }
|
|||||||
webpki = { version = "0.21", optional = true }
|
webpki = { version = "0.21", optional = true }
|
||||||
webpki-roots = { version = "0.19", optional = true }
|
webpki-roots = { version = "0.19", optional = true }
|
||||||
rustls-native-certs = { version = "0.3", optional = true }
|
rustls-native-certs = { version = "0.3", optional = true }
|
||||||
|
serde = { version = "1", optional = true }
|
||||||
serde_json = { version = "1", optional = true }
|
serde_json = { version = "1", optional = true }
|
||||||
encoding = { version = "0.2", optional = true }
|
encoding = { version = "0.2", optional = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ use encoding::EncoderTrap;
|
|||||||
|
|
||||||
#[cfg(feature = "json")]
|
#[cfg(feature = "json")]
|
||||||
use super::SerdeValue;
|
use super::SerdeValue;
|
||||||
#[cfg(feature = "json")]
|
|
||||||
use serde_json;
|
|
||||||
|
|
||||||
/// The different kinds of bodies to send.
|
/// The different kinds of bodies to send.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use crate::stream::Stream;
|
|||||||
use crate::unit::Unit;
|
use crate::unit::Unit;
|
||||||
|
|
||||||
#[cfg(feature = "json")]
|
#[cfg(feature = "json")]
|
||||||
use serde_json;
|
use serde::de::DeserializeOwned;
|
||||||
|
|
||||||
#[cfg(feature = "charset")]
|
#[cfg(feature = "charset")]
|
||||||
use encoding::label::encoding_from_whatwg_label;
|
use encoding::label::encoding_from_whatwg_label;
|
||||||
@@ -382,16 +382,23 @@ impl Response {
|
|||||||
/// Example:
|
/// Example:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # use serde::Deserialize;
|
||||||
|
///
|
||||||
|
/// #[derive(Deserialize)]
|
||||||
|
/// struct Hello {
|
||||||
|
/// hello: String,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
/// let resp =
|
/// let resp =
|
||||||
/// ureq::get("https://ureq.s3.eu-central-1.amazonaws.com/hello_world.json")
|
/// ureq::get("https://ureq.s3.eu-central-1.amazonaws.com/hello_world.json")
|
||||||
/// .call();
|
/// .call();
|
||||||
///
|
///
|
||||||
/// let json = resp.into_json().unwrap();
|
/// let json = resp.into_json::<Hello>().unwrap();
|
||||||
///
|
///
|
||||||
/// assert_eq!(json["hello"], "world");
|
/// assert_eq!(json.hello, "world");
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(feature = "json")]
|
#[cfg(feature = "json")]
|
||||||
pub fn into_json(self) -> IoResult<serde_json::Value> {
|
pub fn into_json<T: DeserializeOwned>(self) -> IoResult<T> {
|
||||||
let reader = self.into_reader();
|
let reader = self.into_reader();
|
||||||
serde_json::from_reader(reader).map_err(|e| {
|
serde_json::from_reader(reader).map_err(|e| {
|
||||||
IoError::new(
|
IoError::new(
|
||||||
@@ -723,15 +730,19 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "json")]
|
#[cfg(feature = "json")]
|
||||||
fn parse_simple_json() {
|
fn parse_simple_json() {
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Hello {
|
||||||
|
hello: String,
|
||||||
|
}
|
||||||
|
|
||||||
let s = "HTTP/1.1 200 OK\r\n\
|
let s = "HTTP/1.1 200 OK\r\n\
|
||||||
\r\n\
|
\r\n\
|
||||||
{\"hello\":\"world\"}";
|
{\"hello\":\"world\"}";
|
||||||
let resp = s.parse::<Response>().unwrap();
|
let resp = s.parse::<Response>().unwrap();
|
||||||
let v = resp.into_json().unwrap();
|
let v = resp.into_json::<Hello>().unwrap();
|
||||||
let compare = "{\"hello\":\"world\"}"
|
assert_eq!(v.hello, "world");
|
||||||
.parse::<serde_json::Value>()
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(v, compare);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -61,6 +61,13 @@ fn body_as_text() {
|
|||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "json")]
|
#[cfg(feature = "json")]
|
||||||
fn body_as_json() {
|
fn body_as_json() {
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Hello {
|
||||||
|
hello: String,
|
||||||
|
}
|
||||||
|
|
||||||
test::set_handler("/body_as_json", |_unit| {
|
test::set_handler("/body_as_json", |_unit| {
|
||||||
test::make_response(
|
test::make_response(
|
||||||
200,
|
200,
|
||||||
@@ -70,8 +77,8 @@ fn body_as_json() {
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
let resp = get("test://host/body_as_json").call();
|
let resp = get("test://host/body_as_json").call();
|
||||||
let json = resp.into_json().unwrap();
|
let json = resp.into_json::<Hello>().unwrap();
|
||||||
assert_eq!(json["hello"], "world");
|
assert_eq!(json.hello, "world");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -17,6 +17,14 @@ fn tls_connection_close() {
|
|||||||
#[cfg(feature = "json")]
|
#[cfg(feature = "json")]
|
||||||
#[test]
|
#[test]
|
||||||
fn agent_set_cookie() {
|
fn agent_set_cookie() {
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct HttpBin {
|
||||||
|
headers: HashMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
let agent = ureq::Agent::default().build();
|
let agent = ureq::Agent::default().build();
|
||||||
let cookie = ureq::Cookie::build("name", "value")
|
let cookie = ureq::Cookie::build("name", "value")
|
||||||
.domain("httpbin.org")
|
.domain("httpbin.org")
|
||||||
@@ -30,10 +38,9 @@ fn agent_set_cookie() {
|
|||||||
assert_eq!(resp.status(), 200);
|
assert_eq!(resp.status(), 200);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"name=value",
|
"name=value",
|
||||||
resp.into_json()
|
resp.into_json::<HttpBin>()
|
||||||
.unwrap()
|
|
||||||
.get("headers")
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
.headers
|
||||||
.get("Cookie")
|
.get("Cookie")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user