Expand description
Named URL reversal — Django’s reverse(name, params) +
get_absolute_url(). Pair with register_url!. Issue #8.
Named URL reversal — Django’s reverse() + get_absolute_url().
Issue #8.
Routes can be registered with a stable name at module-load time
via the register_url! macro, then resolved back to a URL string
through [reverse]. The shape mirrors Django’s URL conf:
use rustango::register_url;
use rustango::urls::reverse;
use std::collections::HashMap;
// At module scope — registers globally via `inventory`.
register_url!("post-detail", "/posts/{id}");
register_url!("home", "/");
// Anywhere at runtime.
let url = reverse("home", &HashMap::new()).unwrap();
assert_eq!(url, "/");
let mut p = HashMap::new();
p.insert("id", "42".to_owned());
let url = reverse("post-detail", &p).unwrap();
assert_eq!(url, "/posts/42");Path-template placeholders use axum 0.8’s {name} shape. Param
values are percent-encoded on substitution so caller-supplied
values are safe even when they contain / / ? / #. Missing
or extra params return a [ReverseError] at call time — there’s
no compile-time check today (would require either codegen or a
shared sentinel; queued as a future enhancement).
Manual sync with axum routes: register_url! only registers
the pattern string with the reverse-lookup table — it does NOT
mount a route on any axum Router. Callers must keep their
axum routing in sync with their register_url! calls. A common
shape is to put both side-by-side in src/urls.rs:
register_url!("post-detail", "/posts/{id}");
pub fn router() -> axum::Router {
axum::Router::new().route("/posts/{id}", get(post_detail_view))
}Duplicate names: two register_url!("name", ...) calls in the
same binary collide silently — reverse picks the first match it
finds in the inventory. Call [duplicates] at boot to surface any
name registered more than once. Future work: a startup validator
that turns this into a clean error before the server binds.
§Namespaced reverse (Django parity #380)
Django’s reverse("app:detail") form works today as a naming
convention — register routes with colon-separated names and they
look up just like any other key:
register_url!("posts:detail", "/posts/{id}");
register_url!("users:detail", "/users/{id}");
let url = reverse("posts:detail", &p).unwrap(); // → "/posts/42"Rustango has no include() concept (every register_url! runs
at module-load and lands in the global registry via inventory),
so the colon prefix is part of the registered name rather than
an auto-applied namespace. The behavior matches Django’s
reverse("app:detail") API surface.
Structs§
- Named
Route - A named route — pattern + stable name. Registered at static-init
time via [
register_url!] (which callsinventory::submit!under the hood) and looked up byreverseat runtime.
Enums§
- Reverse
Error - Failure modes for
reverse.
Functions§
- all_
routes - Snapshot of the route registry — every entry registered via
[
register_url!] across every loaded module. Useful for boot-time diagnostics (seeduplicates) or admin endpoints that surface the URL map. - duplicates
- List every name that’s been registered more than once. Empty vec on a clean registry. Call at app boot — duplicates surface as silent “first wins” otherwise.
- escape_
leading_ slashes - Django-parity
django.utils.http.escape_leading_slashes(url)— escape leading slashes / backslashes on a URL fragment to prevent open-redirect attacks via protocol-relative URLs. - is_
absolute_ url truewhenurllooks absolute — it carries a scheme prefix (https:/mailto:/javascript:/ etc.) OR starts with//(protocol-relative).- is_
relative_ url truewhenurlis path-relative (the inverse ofis_absolute_url). Useful as a positive-frame predicate:- parse_
query_ pairs - Parse a querystring (with or without the leading
?) into a list of(key, value)pairs preserving original order. Malformed pairs (no=, multiple=) are passed through with empty / first-=-split values — same loose interpretation as browsers. - parse_
query_ pairs_ grouped - Django-parity
urllib.parse.parse_qs(qs)— parse a query string into aHashMap<String, Vec<String>>. Same value asparse_query_pairsbut with multi-value keys collected into a vec per key (the canonical “give me everything for key X” shape). - register_
querystring_ filter - Register the Django 5.1
{% querystring %}equivalent as a Tera filter. Issue #19. Takes the current querystring as input and returns a new one with the given overrides applied. - register_
url_ tag - Register Django’s
{% url %}equivalent as a Tera function ontera. Call this once at app setup alongside any other Tera configuration. Issue #14. - reverse
- Resolve a registered name + parameters into a concrete URL string.
- reverse_
owned - Same as
reversebut withStringkeys — convenience for the JSON / template-tag path where keys come from dynamic input. - url_
has_ allowed_ host_ and_ scheme - Django-parity
url_has_allowed_host_and_scheme(url, allowed_hosts, require_https=False)— returnstrueonly whenurlis safe to redirect to from a trusted handler (e.g. the?next=/pathparameter onLoginView/LogoutView). Defends against the open-redirect vector where attacker-controlled input lands in aLocation:header pointing at an external site.