Skip to main content

api_gateway/middleware/
common.rs

1use axum::extract::Request;
2
3pub fn resolve_path(req: &Request, matched_path: &str) -> String {
4    req.extensions()
5        .get::<axum::extract::NestedPath>()
6        .and_then(|np| strip_path_prefix(matched_path, np.as_str()))
7        .unwrap_or_else(|| matched_path.to_owned())
8}
9
10/// Strip `prefix` from `path` only at a segment boundary.
11///
12/// Returns `None` when the prefix doesn't match.  When it does match the
13/// result always starts with `/` (or is `/` when the path equals the prefix).
14fn strip_path_prefix(path: &str, prefix: &str) -> Option<String> {
15    let rest = path.strip_prefix(prefix)?;
16    if rest.is_empty() {
17        // path == prefix exactly  →  root
18        Some("/".to_owned())
19    } else if rest.starts_with('/') {
20        // clean segment boundary  →  keep the slash
21        Some(rest.to_owned())
22    } else {
23        // partial segment overlap (e.g. prefix="/cf", path="/cfish")  →  no match
24        None
25    }
26}
27
28#[cfg(test)]
29#[cfg_attr(coverage_nightly, coverage(off))]
30mod tests {
31    use super::*;
32
33    #[test]
34    fn exact_match_returns_root() {
35        assert_eq!(strip_path_prefix("/cf", "/cf"), Some("/".to_owned()));
36    }
37
38    #[test]
39    fn segment_boundary_strips_correctly() {
40        assert_eq!(
41            strip_path_prefix("/cf/users", "/cf"),
42            Some("/users".to_owned())
43        );
44    }
45
46    #[test]
47    fn partial_segment_overlap_rejected() {
48        assert_eq!(strip_path_prefix("/cfish", "/cf"), None);
49    }
50
51    #[test]
52    fn no_prefix_match_returns_none() {
53        assert_eq!(strip_path_prefix("/other/path", "/cf"), None);
54    }
55
56    #[test]
57    fn nested_prefix_strips_correctly() {
58        assert_eq!(
59            strip_path_prefix("/api/v1/users", "/api/v1"),
60            Some("/users".to_owned())
61        );
62    }
63
64    #[test]
65    fn path_with_params_strips_correctly() {
66        assert_eq!(
67            strip_path_prefix("/cf/users/{id}", "/cf"),
68            Some("/users/{id}".to_owned())
69        );
70    }
71
72    #[test]
73    fn empty_prefix_returns_full_path() {
74        assert_eq!(strip_path_prefix("/users", ""), Some("/users".to_owned()));
75    }
76}