Skip to main content

rustapi_core/router/
method_router.rs

1use crate::handler::{into_boxed_handler, BoxedHandler, Handler};
2use http::Method;
3use rustapi_openapi::Operation;
4use std::collections::HashMap;
5
6/// HTTP method router for a single path
7pub struct MethodRouter {
8    pub(super) handlers: HashMap<Method, BoxedHandler>,
9    pub(crate) operations: HashMap<Method, Operation>,
10    pub(crate) component_registrars: Vec<fn(&mut rustapi_openapi::OpenApiSpec)>,
11}
12
13impl Clone for MethodRouter {
14    fn clone(&self) -> Self {
15        Self {
16            handlers: self.handlers.clone(),
17            operations: self.operations.clone(),
18            component_registrars: self.component_registrars.clone(),
19        }
20    }
21}
22
23impl MethodRouter {
24    /// Create a new empty method router
25    pub fn new() -> Self {
26        Self {
27            handlers: HashMap::new(),
28            operations: HashMap::new(),
29            component_registrars: Vec::new(),
30        }
31    }
32
33    /// Add a handler for a specific method
34    fn on(
35        mut self,
36        method: Method,
37        handler: BoxedHandler,
38        operation: Operation,
39        component_registrar: fn(&mut rustapi_openapi::OpenApiSpec),
40    ) -> Self {
41        self.handlers.insert(method.clone(), handler);
42        self.operations.insert(method, operation);
43        self.component_registrars.push(component_registrar);
44        self
45    }
46
47    /// Get handler for a method
48    pub(crate) fn get_handler(&self, method: &Method) -> Option<&BoxedHandler> {
49        self.handlers.get(method)
50    }
51
52    /// Get allowed methods for 405 response
53    pub(crate) fn allowed_methods(&self) -> Vec<Method> {
54        self.handlers.keys().cloned().collect()
55    }
56
57    /// Create from pre-boxed handlers (internal use)
58    pub(crate) fn from_boxed(handlers: HashMap<Method, BoxedHandler>) -> Self {
59        Self {
60            handlers,
61            operations: HashMap::new(), // Operations lost when using raw boxed handlers for now
62            component_registrars: Vec::new(),
63        }
64    }
65
66    /// Insert a pre-boxed handler and its OpenAPI operation (internal use).
67    ///
68    /// Panics if the same method is inserted twice for the same path.
69    pub(crate) fn insert_boxed_with_operation(
70        &mut self,
71        method: Method,
72        handler: BoxedHandler,
73        operation: Operation,
74        component_registrar: fn(&mut rustapi_openapi::OpenApiSpec),
75    ) {
76        if self.handlers.contains_key(&method) {
77            panic!(
78                "Duplicate handler for method {} on the same path",
79                method.as_str()
80            );
81        }
82
83        self.handlers.insert(method.clone(), handler);
84        self.operations.insert(method, operation);
85        self.component_registrars.push(component_registrar);
86    }
87
88    /// Add a GET handler
89    pub fn get<H, T>(self, handler: H) -> Self
90    where
91        H: Handler<T>,
92        T: 'static,
93    {
94        let mut op = Operation::new();
95        H::update_operation(&mut op);
96        self.on(
97            Method::GET,
98            into_boxed_handler(handler),
99            op,
100            <H as Handler<T>>::register_components,
101        )
102    }
103
104    /// Add a POST handler
105    pub fn post<H, T>(self, handler: H) -> Self
106    where
107        H: Handler<T>,
108        T: 'static,
109    {
110        let mut op = Operation::new();
111        H::update_operation(&mut op);
112        self.on(
113            Method::POST,
114            into_boxed_handler(handler),
115            op,
116            <H as Handler<T>>::register_components,
117        )
118    }
119
120    /// Add a PUT handler
121    pub fn put<H, T>(self, handler: H) -> Self
122    where
123        H: Handler<T>,
124        T: 'static,
125    {
126        let mut op = Operation::new();
127        H::update_operation(&mut op);
128        self.on(
129            Method::PUT,
130            into_boxed_handler(handler),
131            op,
132            <H as Handler<T>>::register_components,
133        )
134    }
135
136    /// Add a PATCH handler
137    pub fn patch<H, T>(self, handler: H) -> Self
138    where
139        H: Handler<T>,
140        T: 'static,
141    {
142        let mut op = Operation::new();
143        H::update_operation(&mut op);
144        self.on(
145            Method::PATCH,
146            into_boxed_handler(handler),
147            op,
148            <H as Handler<T>>::register_components,
149        )
150    }
151
152    /// Add a DELETE handler
153    pub fn delete<H, T>(self, handler: H) -> Self
154    where
155        H: Handler<T>,
156        T: 'static,
157    {
158        let mut op = Operation::new();
159        H::update_operation(&mut op);
160        self.on(
161            Method::DELETE,
162            into_boxed_handler(handler),
163            op,
164            <H as Handler<T>>::register_components,
165        )
166    }
167}
168
169impl Default for MethodRouter {
170    fn default() -> Self {
171        Self::new()
172    }
173}
174
175/// Create a GET route handler
176pub fn get<H, T>(handler: H) -> MethodRouter
177where
178    H: Handler<T>,
179    T: 'static,
180{
181    let mut op = Operation::new();
182    H::update_operation(&mut op);
183    MethodRouter::new().on(
184        Method::GET,
185        into_boxed_handler(handler),
186        op,
187        <H as Handler<T>>::register_components,
188    )
189}
190
191/// Create a POST route handler
192pub fn post<H, T>(handler: H) -> MethodRouter
193where
194    H: Handler<T>,
195    T: 'static,
196{
197    let mut op = Operation::new();
198    H::update_operation(&mut op);
199    MethodRouter::new().on(
200        Method::POST,
201        into_boxed_handler(handler),
202        op,
203        <H as Handler<T>>::register_components,
204    )
205}
206
207/// Create a PUT route handler
208pub fn put<H, T>(handler: H) -> MethodRouter
209where
210    H: Handler<T>,
211    T: 'static,
212{
213    let mut op = Operation::new();
214    H::update_operation(&mut op);
215    MethodRouter::new().on(
216        Method::PUT,
217        into_boxed_handler(handler),
218        op,
219        <H as Handler<T>>::register_components,
220    )
221}
222
223/// Create a PATCH route handler
224pub fn patch<H, T>(handler: H) -> MethodRouter
225where
226    H: Handler<T>,
227    T: 'static,
228{
229    let mut op = Operation::new();
230    H::update_operation(&mut op);
231    MethodRouter::new().on(
232        Method::PATCH,
233        into_boxed_handler(handler),
234        op,
235        <H as Handler<T>>::register_components,
236    )
237}
238
239/// Create a DELETE route handler
240pub fn delete<H, T>(handler: H) -> MethodRouter
241where
242    H: Handler<T>,
243    T: 'static,
244{
245    let mut op = Operation::new();
246    H::update_operation(&mut op);
247    MethodRouter::new().on(
248        Method::DELETE,
249        into_boxed_handler(handler),
250        op,
251        <H as Handler<T>>::register_components,
252    )
253}