Skip to content

Commit 7ec81c3

Browse files
authored
Merge pull request #162 from plippe/move-querystring-tests-from-tide
Move querystring tests from tide
2 parents 6aa5b33 + 6e2eeef commit 7ec81c3

File tree

2 files changed

+64
-7
lines changed

2 files changed

+64
-7
lines changed

src/request.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::headers::{
1414
};
1515
use crate::mime::Mime;
1616
use crate::trailers::{self, Trailers};
17-
use crate::{Body, Extensions, Method, Url, Version};
17+
use crate::{Body, Extensions, Method, StatusCode, Url, Version};
1818

1919
pin_project_lite::pin_project! {
2020
/// An HTTP request.
@@ -627,12 +627,15 @@ impl Request {
627627
/// # Ok(()) }
628628
/// ```
629629
pub fn query<T: serde::de::DeserializeOwned>(&self) -> crate::Result<T> {
630-
use std::io::{Error, ErrorKind};
631-
let query = self
632-
.url
633-
.query()
634-
.ok_or_else(|| Error::from(ErrorKind::InvalidData))?;
635-
Ok(serde_urlencoded::from_str(query)?)
630+
// Default to an empty query string if no query parameter has been specified.
631+
// This allows successful deserialisation of structs where all fields are optional
632+
// when none of those fields has actually been passed by the caller.
633+
let query = self.url().query().unwrap_or("");
634+
serde_urlencoded::from_str(query).map_err(|e| {
635+
// Return the displayable version of the deserialisation error to the caller
636+
// for easier debugging.
637+
crate::Error::from_str(StatusCode::BadRequest, format!("{}", e))
638+
})
636639
}
637640

638641
/// Set the URL querystring.

tests/querystring.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use http_types::{url::Url, Method};
2+
use serde::Deserialize;
3+
4+
#[derive(Deserialize)]
5+
struct Params {
6+
msg: String,
7+
}
8+
9+
#[derive(Deserialize)]
10+
struct OptionalParams {
11+
_msg: Option<String>,
12+
_time: Option<u64>,
13+
}
14+
15+
#[test]
16+
fn successfully_deserialize_query() {
17+
let req = http_types::Request::new(
18+
Method::Get,
19+
Url::parse("http://example.com/?msg=Hello").unwrap(),
20+
);
21+
22+
let params = req.query::<Params>();
23+
assert!(params.is_ok());
24+
assert_eq!(params.unwrap().msg, "Hello");
25+
}
26+
27+
#[test]
28+
fn unsuccessfully_deserialize_query() {
29+
let req = http_types::Request::new(Method::Get, Url::parse("http://example.com/").unwrap());
30+
31+
let params = req.query::<Params>();
32+
assert!(params.is_err());
33+
assert_eq!(params.err().unwrap().to_string(), "missing field `msg`");
34+
}
35+
36+
#[test]
37+
fn malformatted_query() {
38+
let req = http_types::Request::new(
39+
Method::Get,
40+
Url::parse("http://example.com/?error=should_fail").unwrap(),
41+
);
42+
43+
let params = req.query::<Params>();
44+
assert!(params.is_err());
45+
assert_eq!(params.err().unwrap().to_string(), "missing field `msg`");
46+
}
47+
48+
#[test]
49+
fn empty_query_string_for_struct_with_no_required_fields() {
50+
let req = http_types::Request::new(Method::Get, Url::parse("http://example.com").unwrap());
51+
52+
let params = req.query::<OptionalParams>();
53+
assert!(params.is_ok());
54+
}

0 commit comments

Comments
 (0)