Skip to content

Commit 812a4d6

Browse files
feat(ddcommon): Extend path on Endpoint
1 parent a0b92b6 commit 812a4d6

File tree

1 file changed

+63
-0
lines changed

1 file changed

+63
-0
lines changed

ddcommon/src/lib.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#![cfg_attr(not(test), deny(clippy::todo))]
77
#![cfg_attr(not(test), deny(clippy::unimplemented))]
88

9+
use http::{uri::PathAndQuery, Uri};
910
use hyper::{
1011
header::HeaderValue,
1112
http::uri::{self},
@@ -229,6 +230,40 @@ impl Endpoint {
229230
/// Default value for the timeout field in milliseconds.
230231
pub const DEFAULT_TIMEOUT: u64 = 3_000;
231232

233+
/// Add a path to the url of an `Endpoint`.
234+
///
235+
/// The given path must start with a slash (e.g. "/v0.4/traces").
236+
/// Returns an error if the path is not valid.
237+
pub fn add_path(&mut self, path: &str) -> anyhow::Result<()> {
238+
let mut parts = self.url.clone().into_parts();
239+
parts.path_and_query = Some(match parts.path_and_query {
240+
Some(pq) => {
241+
let p = pq.path();
242+
let mut p = p.strip_suffix('/').unwrap_or(p).to_owned();
243+
p.push_str(path);
244+
if let Some(q) = pq.query() {
245+
p.push('?');
246+
p.push_str(q);
247+
}
248+
PathAndQuery::from_str(p.as_str())
249+
}
250+
None => PathAndQuery::from_str(path),
251+
}?);
252+
self.url = Uri::from_parts(parts)?;
253+
Ok(())
254+
}
255+
256+
/// Create a new `Endpoint` by extending the url with the given path.
257+
///
258+
/// The given path must start with a slash (e.g. "/v0.4/traces").
259+
/// Returns an error if the path is not valid.
260+
/// All the other fields are copied.
261+
pub fn try_clone_with_subpath(&self, path: &str) -> anyhow::Result<Self> {
262+
let mut endpoint = self.clone();
263+
endpoint.add_path(path)?;
264+
Ok(endpoint)
265+
}
266+
232267
/// Return a request builder with the following headers:
233268
/// - User agent
234269
/// - Api key
@@ -286,3 +321,31 @@ impl Endpoint {
286321
}
287322
}
288323
}
324+
325+
#[cfg(test)]
326+
mod tests {
327+
use super::*;
328+
329+
#[test]
330+
fn test_add_path() {
331+
let test_cases = [
332+
("http://test.com/", "/foo", "http://test.com/foo"),
333+
("http://test.com/bar", "/foo", "http://test.com/bar/foo"),
334+
(
335+
"http://test.com/bar",
336+
"/foo/baz",
337+
"http://test.com/bar/foo/baz",
338+
),
339+
(
340+
"http://test.com/bar?data=dog&product=apm",
341+
"/foo/baz",
342+
"http://test.com/bar/foo/baz?data=dog&product=apm",
343+
),
344+
];
345+
for (url, path, expected) in test_cases {
346+
let mut endpoint = Endpoint::from_url(url.parse().unwrap());
347+
endpoint.add_path(path).unwrap();
348+
assert_eq!(endpoint.url, expected);
349+
}
350+
}
351+
}

0 commit comments

Comments
 (0)