Skip to content

Commit 722ee7a

Browse files
committed
Re-implement json-using-serde feature
This feature was removed when we gutted `minreq` after forking it. Turns out we need it to be able to use `bitreq` in `jsonrpc`. Re-implement the feature by copying code from `minreq`.
1 parent e022b7c commit 722ee7a

File tree

7 files changed

+94
-1
lines changed

7 files changed

+94
-1
lines changed

Cargo-minimal.lock

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ dependencies = [
165165
"rustls",
166166
"rustls-native-certs",
167167
"rustls-webpki",
168+
"serde",
169+
"serde_json",
168170
"tiny_http",
169171
"tokio",
170172
"tokio-rustls",

Cargo-recent.lock

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ dependencies = [
165165
"rustls",
166166
"rustls-native-certs",
167167
"rustls-webpki",
168+
"serde",
169+
"serde_json",
168170
"tiny_http",
169171
"tokio",
170172
"tokio-rustls",

bitreq/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ maintenance = { status = "experimental" }
2020
urlencoding = { version = "2.1.0", optional = true }
2121
# For the punycode feature:
2222
punycode = { version = "0.4.1", optional = true }
23+
# For the json-using-serde feature:
24+
serde = { version = "1.0.101", optional = true }
25+
serde_json = { version = "1.0.0", optional = true }
2326
# For the proxy feature:
2427
base64 = { version = "0.22", optional = true }
2528
# For the https features:
@@ -37,7 +40,7 @@ tiny_http = "0.12"
3740
chrono = "0.4.0"
3841

3942
[package.metadata.docs.rs]
40-
features = ["proxy", "https", "punycode"]
43+
features = ["json-using-serde", "proxy", "https", "punycode"]
4144

4245
[features]
4346
default = ["std"]
@@ -46,6 +49,7 @@ log = ["dep:log"]
4649
https = ["https-rustls"]
4750
https-rustls = ["rustls", "webpki-roots", "rustls-webpki"]
4851
https-rustls-probe = ["rustls", "rustls-native-certs"]
52+
json-using-serde = ["serde", "serde_json"]
4953
proxy = ["base64"]
5054
async = ["tokio", "std"]
5155
async-https = ["async", "https-rustls", "tokio-rustls"]

bitreq/src/error.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ use std::{error, io};
99
// what the user might want to handle? This error doesn't really invite graceful
1010
// handling.
1111
pub enum Error {
12+
#[cfg(feature = "json-using-serde")]
13+
/// Ran into a Serde error.
14+
SerdeJsonError(serde_json::Error),
1215
/// The response body contains invalid UTF-8, so the `as_str()`
1316
/// conversion failed.
1417
InvalidUtf8InBody(str::Utf8Error),
@@ -88,6 +91,8 @@ impl fmt::Display for Error {
8891
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
8992
use Error::*;
9093
match self {
94+
#[cfg(feature = "json-using-serde")]
95+
SerdeJsonError(err) => write!(f, "{}", err),
9196
#[cfg(feature = "std")]
9297
IoError(err) => write!(f, "{}", err),
9398
InvalidUtf8InBody(err) => write!(f, "{}", err),
@@ -124,6 +129,8 @@ impl error::Error for Error {
124129
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
125130
use Error::*;
126131
match self {
132+
#[cfg(feature = "json-using-serde")]
133+
SerdeJsonError(err) => Some(err),
127134
#[cfg(feature = "std")]
128135
IoError(err) => Some(err),
129136
InvalidUtf8InBody(err) => Some(err),

bitreq/src/request.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,26 @@ impl Request {
173173
self
174174
}
175175

176+
/// Converts given argument to JSON and sets it as body.
177+
///
178+
/// # Errors
179+
///
180+
/// Returns
181+
/// [`SerdeJsonError`](enum.Error.html#variant.SerdeJsonError) if
182+
/// Serde runs into a problem when converting `body` into a
183+
/// string.
184+
#[cfg(feature = "json-using-serde")]
185+
pub fn with_json<T: serde::ser::Serialize>(mut self, body: &T) -> Result<Request, Error> {
186+
self.headers.insert(
187+
"Content-Type".to_string(),
188+
"application/json; charset=UTF-8".to_string(),
189+
);
190+
match serde_json::to_string(&body) {
191+
Ok(json) => Ok(self.with_body(json)),
192+
Err(err) => Err(Error::SerdeJsonError(err)),
193+
}
194+
}
195+
176196
/// Sets the request timeout in seconds.
177197
pub fn with_timeout(mut self, timeout: u64) -> Request {
178198
self.timeout = Some(timeout);

bitreq/src/response.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,45 @@ impl Response {
127127
/// # fn main() -> Result<(), Box<dyn std::error::Error>> { Ok(()) }
128128
/// ```
129129
pub fn into_bytes(self) -> Vec<u8> { self.body }
130+
131+
/// Converts JSON body to a `struct` using Serde.
132+
///
133+
/// # Errors
134+
///
135+
/// Returns
136+
/// [`SerdeJsonError`](enum.Error.html#variant.SerdeJsonError) if
137+
/// Serde runs into a problem, or
138+
/// [`InvalidUtf8InBody`](enum.Error.html#variant.InvalidUtf8InBody)
139+
/// if the body is not UTF-8.
140+
///
141+
/// # Example
142+
/// In case compiler cannot figure out return type you might need to declare it explicitly:
143+
///
144+
/// ```no_run
145+
/// use serde_json::Value;
146+
///
147+
/// # fn main() -> Result<(), minreq::Error> {
148+
/// # let url_to_json_resource = "http://example.org/resource.json";
149+
/// // Value could be any type that implements Deserialize!
150+
/// let user = minreq::get(url_to_json_resource).send()?.json::<Value>()?;
151+
/// println!("User name is '{}'", user["name"]);
152+
/// # Ok(())
153+
/// # }
154+
/// ```
155+
#[cfg(feature = "json-using-serde")]
156+
pub fn json<'a, T>(&'a self) -> Result<T, Error>
157+
where
158+
T: serde::de::Deserialize<'a>,
159+
{
160+
let str = match self.as_str() {
161+
Ok(str) => str,
162+
Err(_) => return Err(Error::InvalidUtf8InResponse),
163+
};
164+
match serde_json::from_str(str) {
165+
Ok(json) => Ok(json),
166+
Err(err) => Err(Error::SerdeJsonError(err)),
167+
}
168+
}
130169
}
131170

132171
/// An HTTP response, which is loaded lazily.

bitreq/tests/main.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,25 @@ fn test_https() {
1414
assert_eq!(get_status_code(bitreq::get("https://example.com").send()), 200,);
1515
}
1616

17+
#[test]
18+
#[cfg(feature = "json-using-serde")]
19+
fn test_json_using_serde() {
20+
const JSON_SRC: &str = r#"{
21+
"str": "Json test",
22+
"num": 42
23+
}"#;
24+
25+
setup();
26+
let original_json: serde_json::Value = serde_json::from_str(JSON_SRC).unwrap();
27+
let response = bitreq::post(url("/echo"))
28+
.with_json(&original_json)
29+
.unwrap()
30+
.send()
31+
.unwrap();
32+
let actual_json: serde_json::Value = response.json().unwrap();
33+
assert_eq!(&actual_json, &original_json);
34+
}
35+
1736
#[test]
1837
fn test_timeout_too_low() {
1938
setup();

0 commit comments

Comments
 (0)