Skip to content

DuskSystems/wayfind

Repository files navigation

license: MIT/Apache-2.0 crates.io documentation

rust: 1.63+ unsafe: forbidden wasm: compatible

codspeed codecov

wayfind

A speedy, flexible router for Rust.

Why another router?

wayfind attempts to bridge the gap between existing Rust router options:

  • fast routers, lacking in flexibility
  • flexible routers, lacking in speed

Real-world projects often need fancy routing capabilities, such as projects ported from frameworks like Ruby on Rails, or those adhering to specifications like the Open Container Initiative (OCI) Distribution Specification.

The goal of wayfind is to remain competitive with the fastest libraries, while offering advanced routing features when needed. Unused features shouldn't impact performance - you only pay for what you use.

Showcase

[dependencies]
wayfind = "0.8"
use std::error::Error;
use wayfind::Router;

fn main() -> Result<(), Box<dyn Error>> {
    let mut router = Router::new();
    router.insert("/pet(/)", 1)?;
    router.insert("/pet/findByStatus(/)", 2)?;
    router.insert("/pet/findByTags(/)", 3)?;
    router.insert("/pet/{pet}(/)", 4)?;
    router.insert("/pet/{petId:u16}/uploadImage(/)", 5)?;
    router.insert("/store/inventory(/)", 6)?;
    router.insert("/store/order(/{orderId:u16})(/)", 7)?;
    router.insert("/user(/)", 8)?;
    router.insert("/user/createWithList(/)", 9)?;
    router.insert("/user/login(/)", 10)?;
    router.insert("/user/logout(/)", 11)?;
    router.insert("/user/{username}(/)", 12)?;
    router.insert("/{*catch_all}", 13)?;

    let search = router.search("/pet").unwrap();
    assert_eq!(*search.data, 1);

    let search = router.search("/pet/").unwrap();
    assert_eq!(*search.data, 1);

    let search = router.search("/pet/123/uploadImage").unwrap();
    assert_eq!(*search.data, 5);
    assert_eq!(search.parameters[0], ("petId", "123"));

    let search = router.search("/store/order").unwrap();
    assert_eq!(*search.data, 7);

    let search = router.search("/store/order/456").unwrap();
    assert_eq!(*search.data, 7);
    assert_eq!(search.parameters[0], ("orderId", "456"));

    let search = router.search("/user/alice").unwrap();
    assert_eq!(*search.data, 12);
    assert_eq!(search.parameters[0], ("username", "alice"));

    let search = router.search("/unknown/path").unwrap();
    assert_eq!(*search.data, 13);
    assert_eq!(search.parameters[0], ("catch_all", "unknown/path"));

    println!("{router}");
    Ok(())
}
/
├─ pet [*]
│  ╰─ / [*]
│     ├─ findBy
│     │  ├─ Status [*]
│     │  │  ╰─ / [*]
│     │  ╰─ Tags [*]
│     │     ╰─ / [*]
│     ├─ {petId:u16}
│     │  ╰─ /uploadImage [*]
│     │     ╰─ / [*]
│     ╰─ {pet} [*]
│        ╰─ / [*]
├─ store/
│  ├─ inventory [*]
│  │  ╰─ / [*]
│  ╰─ order [*]
│     ╰─ / [*]
│        ╰─ {orderId:u16} [*]
│           ╰─ / [*]
├─ user [*]
│  ╰─ / [*]
│     ├─ createWithList [*]
│     │  ╰─ / [*]
│     ├─ log
│     │  ├─ in [*]
│     │  │  ╰─ / [*]
│     │  ╰─ out [*]
│     │     ╰─ / [*]
│     ╰─ {username} [*]
│        ╰─ / [*]
╰─ {*catch_all} [*]

Performance

wayfind is fast, and appears to be competitive against other top performers in all benchmarks we currently run.

See BENCHMARKING.md for the results.

License

wayfind is licensed under the terms of both the MIT License and the Apache License (Version 2.0).

Inspirations

  • poem: Initial experimentations started out as a Poem router fork
  • matchit: Performance leader among pre-existing routers
  • path-tree: Extensive testing and router display feature
  • ASP.NET Core: Constraints-based approach to routing