Provide .method() and .query_params()

This commit is contained in:
Martin Algesten
2021-01-26 20:59:55 +01:00
parent c4c1618042
commit 239ba342a2
3 changed files with 88 additions and 46 deletions

View File

@@ -1,4 +1,4 @@
use url::Url;
use url::{ParseError, Url};
use std::error;
use std::fmt::{self, Display};
@@ -315,6 +315,14 @@ impl From<Transport> for Error {
}
}
impl From<ParseError> for Error {
fn from(err: ParseError) -> Self {
ErrorKind::InvalidUrl
.msg(&format!("failed to parse URL: {:?}", err))
.src(err)
}
}
impl fmt::Display for ErrorKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {

View File

@@ -4,7 +4,6 @@ use std::{fmt, time};
use url::{form_urlencoded, Url};
use crate::body::Payload;
use crate::error::ErrorKind;
use crate::header::{self, Header};
use crate::unit::{self, Unit};
use crate::Response;
@@ -15,10 +14,29 @@ use super::SerdeValue;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone)]
enum Urlish {
Url(Url),
Str(String),
#[derive(Clone)]
struct ParsedUrl(std::result::Result<Url, url::ParseError>);
impl fmt::Display for ParsedUrl {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Ok(url) = &self.0 {
write!(f, "{}", url.as_str())
} else {
write!(f, "{:?}", self.0)
}
}
}
impl From<String> for ParsedUrl {
fn from(s: String) -> Self {
ParsedUrl(s.parse())
}
}
impl From<Url> for ParsedUrl {
fn from(url: Url) -> Self {
ParsedUrl(Ok(url))
}
}
/// Request instances are builders that creates a request.
@@ -36,53 +54,38 @@ enum Urlish {
pub struct Request {
agent: Agent,
method: String,
url: Urlish,
parsed_url: ParsedUrl,
error_on_non_2xx: bool,
headers: Vec<Header>,
query_params: Vec<(String, String)>,
timeout: Option<time::Duration>,
}
impl fmt::Display for Urlish {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Urlish::Url(u) => write!(f, "{}", u),
Urlish::Str(s) => write!(f, "{}", s),
}
}
}
impl fmt::Debug for Request {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"Request({} {} {:?}, {:?})",
self.method, self.url, self.query_params, self.headers
"Request({} {}, {:?})",
self.method, self.parsed_url, self.headers
)
}
}
impl Request {
pub(crate) fn new(agent: Agent, method: String, url: String) -> Request {
Request {
agent,
method,
url: Urlish::Str(url),
headers: vec![],
error_on_non_2xx: true,
query_params: vec![],
timeout: None,
}
Self::_new(agent, method, url.into())
}
pub(crate) fn with_url(agent: Agent, method: String, url: Url) -> Request {
Self::_new(agent, method, url.into())
}
fn _new(agent: Agent, method: String, parsed_url: ParsedUrl) -> Request {
Request {
agent,
method,
url: Urlish::Url(url),
parsed_url,
headers: vec![],
error_on_non_2xx: true,
query_params: vec![],
timeout: None,
}
}
@@ -115,17 +118,8 @@ impl Request {
for h in &self.headers {
h.validate()?;
}
let mut url: Url = match self.url {
Urlish::Url(u) => u,
Urlish::Str(s) => s.parse().map_err(|e| {
ErrorKind::InvalidUrl
.msg(&format!("failed to parse URL: {:?}", e))
.src(e)
})?,
};
for (name, value) in self.query_params {
url.query_pairs_mut().append_pair(&name, &value);
}
let url = self.parsed_url.0?;
let deadline = match self.timeout.or(self.agent.config.timeout) {
None => None,
Some(timeout) => {
@@ -349,7 +343,7 @@ impl Request {
/// ```
/// # fn main() -> Result<(), ureq::Error> {
/// # ureq::is_test(true);
/// let resp = ureq::get("http://httpbin.org/response-headers")
/// let resp = ureq::get("http://httpbin.org/get")
/// .query("format", "json")
/// .query("dest", "/login")
/// .call()?;
@@ -357,10 +351,50 @@ impl Request {
/// # }
/// ```
pub fn query(mut self, param: &str, value: &str) -> Self {
self.query_params
.push((param.to_string(), value.to_string()));
if let Ok(url) = &mut self.parsed_url.0 {
url.query_pairs_mut().append_pair(param, value);
}
self
}
/// Returns the value of the request method. Something like `GET`, `POST`, `PUT` etc.
///
/// ```
/// let req = ureq::put("http://httpbin.org/put");
///
/// assert_eq!(req.method(), "PUT");
/// ```
pub fn method(&self) -> &str {
&self.method
}
/// Returns all query parameters as a vector of key-value pairs.
///
/// ```
/// # fn main() -> Result<(), ureq::Error> {
/// # ureq::is_test(true);
/// let req = ureq::get("http://httpbin.org/get")
/// .query("foo", "42")
/// .query("foo", "43");
///
/// assert_eq!(req.query_params(), vec![
/// ("foo".to_string(), "42".to_string()),
/// ("foo".to_string(), "43".to_string())
/// ]);
/// # Ok(())
/// # }
/// ```
pub fn query_params(&self) -> Vec<(String, String)> {
let mut ret = vec![];
if let Ok(url) = &self.parsed_url.0 {
for (k, v) in url.query_pairs() {
ret.push((k.into(), v.into()));
}
}
ret
}
}
#[test]

View File

@@ -136,7 +136,7 @@ fn request_debug() {
assert_eq!(
s,
"Request(GET http://localhost/my/page [], [Authorization: abcdef, \
"Request(GET http://localhost/my/page, [Authorization: abcdef, \
Content-Length: 1234, Content-Type: application/json])"
);
@@ -148,7 +148,7 @@ fn request_debug() {
assert_eq!(
s,
"Request(GET http://localhost/my/page?q=z [(\"foo\", \"bar baz\")], [Authorization: abcdef])"
"Request(GET http://localhost/my/page?q=z&foo=bar+baz, [Authorization: abcdef])"
);
}