Merge into_json_deserialize into into_json. (#235)
Followup to #56. At the time, doing this would have been an API break; but we can do this as part of 2.0. This simplifies the API nicely and creates better symmetry between sending bodies and receiving them.
This commit is contained in:
@@ -25,8 +25,7 @@ pub const DEFAULT_CHARACTER_SET: &str = "utf-8";
|
|||||||
///
|
///
|
||||||
/// The `Response` is used to read response headers and decide what to do with the body.
|
/// The `Response` is used to read response headers and decide what to do with the body.
|
||||||
/// Note that the socket connection is open and the body not read until one of
|
/// Note that the socket connection is open and the body not read until one of
|
||||||
/// [`into_reader()`](#method.into_reader), [`into_json()`](#method.into_json),
|
/// [`into_reader()`](#method.into_reader), [`into_json()`](#method.into_json), or
|
||||||
/// [`into_json_deserialize()`](#method.into_json_deserialize) or
|
|
||||||
/// [`into_string()`](#method.into_string) consumes the response.
|
/// [`into_string()`](#method.into_string) consumes the response.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
@@ -343,47 +342,13 @@ impl Response {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Turn this response into a (serde) JSON value of the response body.
|
/// Read the body of this response into a serde_json::Value, or any other type that
|
||||||
|
// implements the [serde::Deserialize] trait.
|
||||||
///
|
///
|
||||||
/// Requires feature `ureq = { version = "*", features = ["json"] }`
|
/// You must use either a type annotation as shown below (`message: Message`), or the
|
||||||
|
/// [turbofish operator] (`::<Type>`) so Rust knows what type you are trying to read.
|
||||||
///
|
///
|
||||||
/// Example:
|
/// [turbofish operator]: https://matematikaadit.github.io/posts/rust-turbofish.html
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # fn main() -> Result<(), ureq::Error> {
|
|
||||||
/// # ureq::is_test(true);
|
|
||||||
/// let json: serde_json::Value = ureq::get("http://example.com/hello_world.json")
|
|
||||||
/// .call()?
|
|
||||||
/// .into_json()?;
|
|
||||||
///
|
|
||||||
/// assert_eq!(json["hello"], "world");
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
#[cfg(feature = "json")]
|
|
||||||
pub fn into_json(self) -> io::Result<serde_json::Value> {
|
|
||||||
use crate::stream::io_err_timeout;
|
|
||||||
use std::error::Error;
|
|
||||||
|
|
||||||
let reader = self.into_reader();
|
|
||||||
serde_json::from_reader(reader).map_err(|e| {
|
|
||||||
// This is to unify TimedOut io::Error in the API.
|
|
||||||
// We make a clone of the original error since serde_json::Error doesn't
|
|
||||||
// let us get the wrapped error instance back.
|
|
||||||
if let Some(ioe) = e.source().and_then(|s| s.downcast_ref::<io::Error>()) {
|
|
||||||
if ioe.kind() == io::ErrorKind::TimedOut {
|
|
||||||
return io_err_timeout(ioe.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
io::Error::new(
|
|
||||||
io::ErrorKind::InvalidData,
|
|
||||||
format!("Failed to read JSON: {}", e),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Turn the body of this response into a type that implements the [serde::Deserialize] trait.
|
|
||||||
///
|
///
|
||||||
/// Requires feature `ureq = { version = "*", features = ["json"] }`
|
/// Requires feature `ureq = { version = "*", features = ["json"] }`
|
||||||
///
|
///
|
||||||
@@ -402,16 +367,44 @@ impl Response {
|
|||||||
/// let message: Message =
|
/// let message: Message =
|
||||||
/// ureq::get("http://example.com/hello_world.json")
|
/// ureq::get("http://example.com/hello_world.json")
|
||||||
/// .call()?
|
/// .call()?
|
||||||
/// .into_json_deserialize()?;
|
/// .into_json()?;
|
||||||
///
|
///
|
||||||
/// assert_eq!(message.hello, "world");
|
/// assert_eq!(message.hello, "world");
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// Or, if you don't want to define a struct to read your JSON into, you can
|
||||||
|
/// use the convenient `serde_json::Value` type to parse arbitrary or unknown
|
||||||
|
/// JSON.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # fn main() -> Result<(), ureq::Error> {
|
||||||
|
/// # ureq::is_test(true);
|
||||||
|
/// let json: serde_json::Value = ureq::get("http://example.com/hello_world.json")
|
||||||
|
/// .call()?
|
||||||
|
/// .into_json()?;
|
||||||
|
///
|
||||||
|
/// assert_eq!(json["hello"], "world");
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
#[cfg(feature = "json")]
|
#[cfg(feature = "json")]
|
||||||
pub fn into_json_deserialize<T: DeserializeOwned>(self) -> io::Result<T> {
|
pub fn into_json<T: DeserializeOwned>(self) -> io::Result<T> {
|
||||||
|
use crate::stream::io_err_timeout;
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
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| {
|
||||||
|
// This is to unify TimedOut io::Error in the API.
|
||||||
|
// We make a clone of the original error since serde_json::Error doesn't
|
||||||
|
// let us get the wrapped error instance back.
|
||||||
|
if let Some(ioe) = e.source().and_then(|s| s.downcast_ref::<io::Error>()) {
|
||||||
|
if ioe.kind() == io::ErrorKind::TimedOut {
|
||||||
|
return io_err_timeout(ioe.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
io::Error::new(
|
io::Error::new(
|
||||||
io::ErrorKind::InvalidData,
|
io::ErrorKind::InvalidData,
|
||||||
format!("Failed to read JSON: {}", e),
|
format!("Failed to read JSON: {}", e),
|
||||||
@@ -717,7 +710,7 @@ mod tests {
|
|||||||
\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: serde_json::Value = resp.into_json().unwrap();
|
||||||
let compare = "{\"hello\":\"world\"}"
|
let compare = "{\"hello\":\"world\"}"
|
||||||
.parse::<serde_json::Value>()
|
.parse::<serde_json::Value>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -738,7 +731,7 @@ mod tests {
|
|||||||
\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_deserialize::<Hello>().unwrap();
|
let v: Hello = resp.into_json::<Hello>().unwrap();
|
||||||
assert_eq!(v.hello, "world");
|
assert_eq!(v.hello, "world");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ fn body_as_json() {
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
let resp = get("test://host/body_as_json").call().unwrap();
|
let resp = get("test://host/body_as_json").call().unwrap();
|
||||||
let json = resp.into_json().unwrap();
|
let json: serde_json::Value = resp.into_json().unwrap();
|
||||||
assert_eq!(json["hello"], "world");
|
assert_eq!(json["hello"], "world");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ fn body_as_json_deserialize() {
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
let resp = get("test://host/body_as_json_deserialize").call().unwrap();
|
let resp = get("test://host/body_as_json_deserialize").call().unwrap();
|
||||||
let json = resp.into_json_deserialize::<Hello>().unwrap();
|
let json: Hello = resp.into_json().unwrap();
|
||||||
assert_eq!(json.hello, "world");
|
assert_eq!(json.hello, "world");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -153,9 +153,9 @@ fn overall_timeout_reading_json() {
|
|||||||
|
|
||||||
let timeout = Duration::from_millis(500);
|
let timeout = Duration::from_millis(500);
|
||||||
let agent = builder().timeout(timeout).build();
|
let agent = builder().timeout(timeout).build();
|
||||||
let resp = agent.get(&url).call().unwrap();
|
let result: Result<serde_json::Value, io::Error> = agent.get(&url).call().unwrap().into_json();
|
||||||
|
|
||||||
match resp.into_json() {
|
match result {
|
||||||
Ok(_) => Err("successful response".to_string()),
|
Ok(_) => Err("successful response".to_string()),
|
||||||
Err(e) => match e.kind() {
|
Err(e) => match e.kind() {
|
||||||
io::ErrorKind::TimedOut => Ok(()),
|
io::ErrorKind::TimedOut => Ok(()),
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ fn agent_set_header() {
|
|||||||
.call()
|
.call()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(resp.status(), 200);
|
assert_eq!(resp.status(), 200);
|
||||||
let json = resp.into_json_deserialize::<HttpBin>().unwrap();
|
let json: HttpBin = resp.into_json().unwrap();
|
||||||
// println!("{:?}", json);
|
// println!("{:?}", json);
|
||||||
assert_eq!("value", json.headers.get("Header").unwrap());
|
assert_eq!("value", json.headers.get("Header").unwrap());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user