96 lines
2.3 KiB
Rust
96 lines
2.3 KiB
Rust
#[derive(Debug)]
|
|
pub struct Url<'a> {
|
|
path_segments: Vec<&'a str>,
|
|
query_params: QueryParams<'a>,
|
|
}
|
|
|
|
pub type QueryParam<'a> = (&'a str, &'a str);
|
|
|
|
pub type QueryParams<'a> = Vec<QueryParam<'a>>;
|
|
|
|
impl Url<'_> {
|
|
pub fn parse(url: &str) -> Url {
|
|
let mut parts = url.splitn(2, '?');
|
|
|
|
let path = parts.next().unwrap_or_default();
|
|
let query = parts.next();
|
|
|
|
Url {
|
|
path_segments: extract_path_segments(path),
|
|
query_params: extract_query_params(query),
|
|
}
|
|
}
|
|
|
|
pub fn path_segments(&self) -> &[&str] {
|
|
self.path_segments.as_slice()
|
|
}
|
|
|
|
pub fn query_params(&self) -> &QueryParams {
|
|
&self.query_params
|
|
}
|
|
}
|
|
|
|
fn extract_path_segments(path: &str) -> Vec<&str> {
|
|
path.split_terminator('/').skip(1).collect()
|
|
}
|
|
|
|
fn extract_query_params(query: Option<&str>) -> Vec<QueryParam> {
|
|
query
|
|
.clone()
|
|
.map(|q| {
|
|
q.split('&')
|
|
.filter_map(|part| {
|
|
if let [key, val] = part.splitn(2, '=').collect::<Vec<&str>>()[..] {
|
|
Some((key, val))
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
.collect()
|
|
})
|
|
.unwrap_or_default()
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn should_extract_path_segments() {
|
|
let path = "/hello/world";
|
|
let segments = extract_path_segments(path);
|
|
|
|
assert_eq!(segments, ["hello", "world"]);
|
|
}
|
|
|
|
#[test]
|
|
fn should_not_extract_tralling_slash_as_empty_segment() {
|
|
let path = "/hello/world/";
|
|
let segments = extract_path_segments(path);
|
|
|
|
assert_eq!(segments, ["hello", "world"]);
|
|
}
|
|
|
|
#[test]
|
|
fn should_extract_query_params() {
|
|
let query_params = Some("lang=rus&keys=apple&keys=banana");
|
|
let params = extract_query_params(query_params);
|
|
|
|
assert_eq!(
|
|
params[..],
|
|
[("lang", "rus"), ("keys", "apple"), ("keys", "banana")]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn should_parse_whole_url() {
|
|
let url = Url::parse("/api/ingredients?lang=rus&keys=apple&keys=banana");
|
|
|
|
assert_eq!(url.path_segments(), ["api", "ingredients"]);
|
|
assert_eq!(
|
|
url.query_params()[..],
|
|
[("lang", "rus"), ("keys", "apple"), ("keys", "banana")]
|
|
)
|
|
}
|
|
}
|