Skip to content

sidrubs/web-route

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Web Route

web-route provides an ergonomic way to define and manage web server routes in Rust.

Most web frameworks define routes using &str templates (e.g. "/foo/{param}"). This approach can become error-prone when you need to:

  • Generate a callable version of a route (with parameters populated), for use in internal redirects, integration tests, etc.
  • Join routes across nested routers — without having to worry about whether strings have leading/trailing slashes or resorting to format!() gymnastics.

Features

  • Cleanly define and join route segments
  • Generate template routes for framework registration
  • Generate populated routes with runtime parameters
  • Slash handling is automatic and consistent

Usage

One can create and join WebRoutes without having to worry about leading and trailing slash pedantics. The resulting routes will always be normalized to have single forward slash separators no matter the operating system.

use web_route::WebRoute;

let foo = WebRoute::new("no/leading/slash/");
let bar = WebRoute::new("/leading/and//trailing/slash/");

// Can join `WebRoute`s.
let joined_route = foo.join(bar);
assert_eq!(&joined_route.to_string(), "/no/leading/slash/leading/and/trailing/slash");

// Can join `String`s and `&str`.
let joined_route = foo.join("/a/str/route");
assert_eq!(&joined_route.to_string(), "/no/leading/slash/a/str/route");

WebRoutes can be serialized and deserialized.

use serde::{Serialize, Deserialize};
use web_route::WebRoute;

#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct FooStruct {
    route: WebRoute
}

let foo_struct = FooStruct {
    route: WebRoute::new("/foo/bar/baz"),
};

let serialized = serde_json::to_string(&foo_struct).unwrap();
let deserialized = serde_json::from_str::<FooStruct>(&serialized).unwrap();

assert_eq!(deserialized, foo_struct);

One would use a ParameterizedRoute when defining routes used by a webserver (e.g. axum)

use web_route::ParameterizedRoute;

let foo = ParameterizedRoute::new("/foo/{foo_id}");
let bar = ParameterizedRoute::new("/bar/{bar_id}");

assert_eq!(&foo.join(bar).to_string(), "/foo/{foo_id}/bar/{bar_id}");

A ParameterizedRoute can be populated with values to produce a WebRoute which can then be used to make a request to the server route it defines.

use serde::{Serialize, Deserialize};
use web_route::ParameterizedRoute;

let foo = ParameterizedRoute::new("/foo/{foo_id}");
let bar = ParameterizedRoute::new("/bar/{bar_id}");

#[derive(Serialize, Deserialize)]
struct Params {
    foo_id: String,
    bar_id: String,
}

let params = Params {
    foo_id: "value_foo".to_owned(),
    bar_id: "value_bar".to_owned(),
};

let web_route = foo.join(bar).to_web_route(&params).unwrap();

assert_eq!(&web_route.to_string(), "/foo/value_foo/bar/value_bar");

For more complete examples, see the examples and integration tests.

Potential Improvements

  • Enable compile-time validation of routes and parameters for even greater safety.

Prior Art

  • TypedPath: The axum-extra crate provides the TypedPath trait with a #[derive(TypedPath)] implementation. It enables type-safe, compile-time-checked population of path parameters and returns a Uri suitable for use in requests. However, it does not appear to offer a clean or ergonomic way to compose or join multiple routes.

Feature Flags

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published