trillium_router/router_ref.rs
1use crate::Router;
2use routefinder::RouteSpec;
3use std::fmt::Debug;
4use trillium::{Handler, Method};
5
6macro_rules! method_ref {
7 ($fn_name:ident, $method:ident) => {
8 method_ref!(
9 $fn_name,
10 $method,
11 concat!(
12 // yep, macro-generated doctests
13 "Registers a handler for the ",
14 stringify!($fn_name),
15 " http method.
16
17```
18# use trillium::Conn;
19# use trillium_router::Router;
20let router = Router::build(|mut router| {
21 router.",
22 stringify!($fn_name),
23 "(\"/some/route\", |conn: Conn| async move {
24 conn.ok(\"success\")
25 });
26});
27
28use trillium_testing::{methods::",
29 stringify!($fn_name),
30 ", assert_ok, assert_not_handled};
31assert_ok!(",
32 stringify!($fn_name),
33 "(\"/some/route\").on(&router), \"success\");
34assert_not_handled!(",
35 stringify!($fn_name),
36 "(\"/other/route\").on(&router));
37```
38"
39 )
40 );
41 };
42
43 ($fn_name:ident, $method:ident, $doc_comment:expr) => {
44 #[doc = $doc_comment]
45 pub fn $fn_name<R>(&mut self, path: R, handler: impl Handler)
46 where
47 R: TryInto<RouteSpec>,
48 R::Error: Debug,
49 {
50 self.0.add(path, Method::$method, handler);
51 }
52 };
53}
54
55/**
56# A `&mut Router` for use with `Router::build`
57
58A wrapper around a `&mut Router` that supports imperative route
59registration. See [`Router::build`] for further documentation.
60*/
61#[derive(Debug)]
62pub struct RouterRef<'r>(&'r mut Router);
63impl<'r> RouterRef<'r> {
64 method_ref!(get, Get);
65 method_ref!(post, Post);
66 method_ref!(put, Put);
67 method_ref!(delete, Delete);
68 method_ref!(patch, Patch);
69
70 /**
71 Appends the handler to all (get, post, put, delete, and patch) methods.
72
73 ```
74 # use trillium::Conn;
75 # use trillium_router::Router;
76 let router = Router::build(|mut router| {
77 router.all("/any", |conn: Conn| async move {
78 let response = format!("you made a {} request to /any", conn.method());
79 conn.ok(response)
80 });
81 });
82
83 use trillium_testing::prelude::*;
84 assert_ok!(get("/any").on(&router), "you made a GET request to /any");
85 assert_ok!(post("/any").on(&router), "you made a POST request to /any");
86 assert_ok!(delete("/any").on(&router), "you made a DELETE request to /any");
87 assert_ok!(patch("/any").on(&router), "you made a PATCH request to /any");
88 assert_ok!(put("/any").on(&router), "you made a PUT request to /any");
89
90 assert_not_handled!(get("/").on(&router));
91 ```
92
93 */
94 pub fn all<R>(&mut self, path: R, handler: impl Handler)
95 where
96 R: TryInto<RouteSpec>,
97 R::Error: Debug,
98 {
99 self.0.add_all(path, handler)
100 }
101
102 /**
103 Appends the handler to each of the provided http methods.
104 ```
105 # use trillium::Conn;
106 # use trillium_router::Router;
107 let router = Router::build(|mut router|{
108 router.any(&["get", "post"], "/get_or_post", |conn: Conn| async move {
109 let response = format!("you made a {} request to /get_or_post", conn.method());
110 conn.ok(response)
111 });
112 });
113
114 use trillium_testing::prelude::*;
115 assert_ok!(get("/get_or_post").on(&router), "you made a GET request to /get_or_post");
116 assert_ok!(post("/get_or_post").on(&router), "you made a POST request to /get_or_post");
117 assert_not_handled!(delete("/any").on(&router));
118 assert_not_handled!(patch("/any").on(&router));
119 assert_not_handled!(put("/any").on(&router));
120 assert_not_handled!(get("/").on(&router));
121 ```
122 */
123 pub fn any<IntoMethod, R>(&mut self, methods: &[IntoMethod], path: R, handler: impl Handler)
124 where
125 R: TryInto<RouteSpec>,
126 R::Error: Debug,
127 IntoMethod: TryInto<Method> + Clone,
128 <IntoMethod as TryInto<Method>>::Error: Debug,
129 {
130 let methods = methods
131 .iter()
132 .cloned()
133 .map(|m| m.try_into().unwrap())
134 .collect::<Vec<_>>();
135
136 self.0.add_any(&methods, path, handler);
137 }
138
139 pub(crate) fn new(router: &'r mut Router) -> Self {
140 Self(router)
141 }
142 /**
143 Registers a handler for a method other than get, put, post, patch, or delete.
144 ```
145 # use trillium::{Conn, Method};
146 # use trillium_router::Router;
147 let router = Router::build(|mut router| {
148 router.add_route("OPTIONS", "/some/route", |conn: Conn| async move {
149 conn.ok("directly handling options")
150 });
151
152 router.add_route(Method::Checkin, "/some/route", |conn: Conn| async move {
153 conn.ok("checkin??")
154 });
155 });
156
157 use trillium_testing::{prelude::*, TestConn};
158 assert_ok!(TestConn::build(Method::Options, "/some/route", ()).on(&router), "directly handling options");
159 assert_ok!(TestConn::build("checkin", "/some/route", ()).on(&router), "checkin??");
160 ```
161 */
162 pub fn add_route<M, R>(&mut self, method: M, path: R, handler: impl Handler)
163 where
164 M: TryInto<Method>,
165 <M as TryInto<Method>>::Error: Debug,
166 R: TryInto<RouteSpec>,
167 R::Error: Debug,
168 {
169 self.0.add(path, method.try_into().unwrap(), handler);
170 }
171
172 /**
173 enable or disable the router's behavior of responding to OPTIONS
174 requests with the supported methods at given path.
175
176 default: enabled
177
178 see crate-level docs for further explanation of the default behavior.
179 */
180 pub fn set_options_handling(&mut self, options_enabled: bool) {
181 self.0.set_options_handling(options_enabled);
182 }
183}