Skip to main content

trillium_router/
lib.rs

1#![forbid(unsafe_code)]
2#![deny(
3    clippy::dbg_macro,
4    missing_copy_implementations,
5    rustdoc::missing_crate_level_docs,
6    missing_debug_implementations,
7    missing_docs,
8    nonstandard_style,
9    unused_qualifications
10)]
11
12//! # Welcome to the trillium router crate!
13//!
14//! This router is built on top of
15//! [routefinder](https://github.com/jbr/routefinder), and the details of
16//! route resolution and definition are documented on that repository.
17//!
18//! ```
19//! use trillium::{Conn, conn_unwrap};
20//! use trillium_router::{Router, RouterConnExt};
21//! use trillium_testing::TestServer;
22//!
23//! # trillium_testing::block_on(async {
24//! let app = TestServer::new(
25//!     Router::new()
26//!         .get("/", |conn: Conn| async move {
27//!             conn.ok("you have reached the index")
28//!         })
29//!         .get("/pages/:page_name", |conn: Conn| async move {
30//!             let page_name = conn_unwrap!(conn.param("page_name"), conn);
31//!             let content = format!("you have reached the page named {}", page_name);
32//!             conn.ok(content)
33//!         }),
34//! )
35//! .await;
36//!
37//! app.get("/")
38//!     .await
39//!     .assert_ok()
40//!     .assert_body("you have reached the index");
41//! app.get("/pages/trillium")
42//!     .await
43//!     .assert_ok()
44//!     .assert_body("you have reached the page named trillium");
45//! app.get("/unknown/route").await.assert_status(404);
46//! # });
47//! ```
48//!
49//! Although this is currently the only trillium router, it is an
50//! important aspect of trillium's architecture that the router uses only
51//! public apis and is interoperable with other router implementations. If
52//! you have different ideas of how a router might work, please publish a
53//! crate! It should be possible to nest different types of routers (and
54//! different versions of router crates) within each other as long as they
55//! all depend on the same version of the `trillium` crate.
56//!
57//! ## Options handling
58//!
59//! By default, the trillium router will reply to an OPTIONS request with
60//! the list of supported http methods at the given route. If the OPTIONS
61//! request is sent for `*`, it responds with the full set of http methods
62//! supported by this router.
63//!
64//! **Note:** This behavior is superceded by an explicit OPTIONS handler
65//! or an `any` handler.
66//!
67//! To disable the default OPTIONS behavior, use
68//! [`Router::without_options_handling`] or
69//! [`RouterRef::set_options_handling`]
70
71#[cfg(test)]
72#[doc = include_str!("../README.md")]
73mod readme {}
74
75mod router;
76pub use router::Router;
77
78mod router_ref;
79pub use router_ref::RouterRef;
80
81mod router_conn_ext;
82pub use router_conn_ext::RouterConnExt;
83
84/// The routes macro represents an experimental macro for defining
85/// routers.
86///
87/// **stability note:** this may be removed entirely if it is not widely
88/// used. please open an issue if you like it, or if you have ideas to
89/// improve it.
90///
91/// ```
92/// use trillium::{conn_unwrap, Conn};
93/// use trillium_router::{routes, RouterConnExt};
94/// use trillium_testing::TestServer;
95///
96/// # trillium_testing::block_on(async {
97/// let router = routes!(
98/// get "/" |conn: Conn| async move { conn.ok("you have reached the index") },
99/// get "/pages/:page_name" |conn: Conn| async move {
100/// let page_name = conn_unwrap!(conn.param("page_name"), conn);
101/// let content = format!("you have reached the page named {}", page_name);
102/// conn.ok(content)
103/// }
104/// );
105///
106/// let app = TestServer::new(router).await;
107/// app.get("/").await
108///     .assert_ok()
109///     .assert_body("you have reached the index");
110/// app.get("/pages/trillium").await
111///     .assert_ok()
112///     .assert_body("you have reached the page named trillium");
113/// app.get("/unknown/route").await
114///     .assert_status(404);
115/// # });
116/// ```
117#[macro_export]
118macro_rules! routes {
119    ($($method:ident $path:literal $(-> )?$handler:expr_2021),+ $(,)?) => {
120	$crate::Router::new()$(
121            .$method($path, $handler)
122        )+;
123    };
124}
125
126/// Builds a new [`Router`]. Alias for [`Router::new`].
127pub fn router() -> Router {
128    Router::new()
129}
130
131pub(crate) struct CapturesNewType<'a, 'b>(routefinder::Captures<'a, 'b>);
132pub(crate) struct RouteSpecNewType(routefinder::RouteSpec);