1use crate::extract::FromRequest;
58use crate::request::Request;
59use crate::response::{IntoResponse, Response};
60use rustapi_openapi::{Operation, OperationModifier, ResponseModifier};
61use std::future::Future;
62use std::marker::PhantomData;
63use std::pin::Pin;
64
65mod sealed {
66 pub trait Sealed {}
67
68 impl<T> Sealed for T where T: Clone + Send + Sync + Sized + 'static {}
69}
70
71pub trait Handler<T>: sealed::Sealed + Clone + Send + Sync + Sized + 'static {
73 type Future: Future<Output = Response> + Send + 'static;
75
76 fn call(self, req: Request) -> Self::Future;
78
79 fn update_operation(op: &mut Operation);
81
82 fn register_components(spec: &mut rustapi_openapi::OpenApiSpec);
84}
85
86pub struct HandlerService<H, T> {
88 handler: H,
89 _marker: PhantomData<fn() -> T>,
90}
91
92impl<H, T> HandlerService<H, T> {
93 pub fn new(handler: H) -> Self {
94 Self {
95 handler,
96 _marker: PhantomData,
97 }
98 }
99}
100
101impl<H: Clone, T> Clone for HandlerService<H, T> {
102 fn clone(&self) -> Self {
103 Self {
104 handler: self.handler.clone(),
105 _marker: PhantomData,
106 }
107 }
108}
109
110impl<F, Fut, Res> Handler<()> for F
114where
115 F: FnOnce() -> Fut + Clone + Send + Sync + 'static,
116 Fut: Future<Output = Res> + Send + 'static,
117 Res: IntoResponse + ResponseModifier,
118{
119 type Future = Pin<Box<dyn Future<Output = Response> + Send>>;
120
121 fn call(self, _req: Request) -> Self::Future {
122 Box::pin(async move { self().await.into_response() })
123 }
124
125 fn update_operation(op: &mut Operation) {
126 Res::update_response(op);
127 }
128
129 fn register_components(spec: &mut rustapi_openapi::OpenApiSpec) {
130 Res::register_components(spec);
131 }
132}
133
134impl<F, Fut, Res, T1> Handler<(T1,)> for F
136where
137 F: FnOnce(T1) -> Fut + Clone + Send + Sync + 'static,
138 Fut: Future<Output = Res> + Send + 'static,
139 Res: IntoResponse + ResponseModifier,
140 T1: FromRequest + OperationModifier + Send + 'static,
141{
142 type Future = Pin<Box<dyn Future<Output = Response> + Send>>;
143
144 fn call(self, mut req: Request) -> Self::Future {
145 Box::pin(async move {
146 let t1 = match T1::from_request(&mut req).await {
147 Ok(v) => v,
148 Err(e) => return e.into_response(),
149 };
150 self(t1).await.into_response()
151 })
152 }
153
154 fn update_operation(op: &mut Operation) {
155 T1::update_operation(op);
156 Res::update_response(op);
157 }
158
159 fn register_components(spec: &mut rustapi_openapi::OpenApiSpec) {
160 T1::register_components(spec);
161 Res::register_components(spec);
162 }
163}
164
165impl<F, Fut, Res, T1, T2> Handler<(T1, T2)> for F
167where
168 F: FnOnce(T1, T2) -> Fut + Clone + Send + Sync + 'static,
169 Fut: Future<Output = Res> + Send + 'static,
170 Res: IntoResponse + ResponseModifier,
171 T1: FromRequest + OperationModifier + Send + 'static,
172 T2: FromRequest + OperationModifier + Send + 'static,
173{
174 type Future = Pin<Box<dyn Future<Output = Response> + Send>>;
175
176 fn call(self, mut req: Request) -> Self::Future {
177 Box::pin(async move {
178 let t1 = match T1::from_request(&mut req).await {
179 Ok(v) => v,
180 Err(e) => return e.into_response(),
181 };
182 let t2 = match T2::from_request(&mut req).await {
183 Ok(v) => v,
184 Err(e) => return e.into_response(),
185 };
186 self(t1, t2).await.into_response()
187 })
188 }
189
190 fn update_operation(op: &mut Operation) {
191 T1::update_operation(op);
192 T2::update_operation(op);
193 Res::update_response(op);
194 }
195
196 fn register_components(spec: &mut rustapi_openapi::OpenApiSpec) {
197 T1::register_components(spec);
198 T2::register_components(spec);
199 Res::register_components(spec);
200 }
201}
202
203impl<F, Fut, Res, T1, T2, T3> Handler<(T1, T2, T3)> for F
205where
206 F: FnOnce(T1, T2, T3) -> Fut + Clone + Send + Sync + 'static,
207 Fut: Future<Output = Res> + Send + 'static,
208 Res: IntoResponse + ResponseModifier,
209 T1: FromRequest + OperationModifier + Send + 'static,
210 T2: FromRequest + OperationModifier + Send + 'static,
211 T3: FromRequest + OperationModifier + Send + 'static,
212{
213 type Future = Pin<Box<dyn Future<Output = Response> + Send>>;
214
215 fn call(self, mut req: Request) -> Self::Future {
216 Box::pin(async move {
217 let t1 = match T1::from_request(&mut req).await {
218 Ok(v) => v,
219 Err(e) => return e.into_response(),
220 };
221 let t2 = match T2::from_request(&mut req).await {
222 Ok(v) => v,
223 Err(e) => return e.into_response(),
224 };
225 let t3 = match T3::from_request(&mut req).await {
226 Ok(v) => v,
227 Err(e) => return e.into_response(),
228 };
229 self(t1, t2, t3).await.into_response()
230 })
231 }
232
233 fn update_operation(op: &mut Operation) {
234 T1::update_operation(op);
235 T2::update_operation(op);
236 T3::update_operation(op);
237 Res::update_response(op);
238 }
239
240 fn register_components(spec: &mut rustapi_openapi::OpenApiSpec) {
241 T1::register_components(spec);
242 T2::register_components(spec);
243 T3::register_components(spec);
244 Res::register_components(spec);
245 }
246}
247
248impl<F, Fut, Res, T1, T2, T3, T4> Handler<(T1, T2, T3, T4)> for F
250where
251 F: FnOnce(T1, T2, T3, T4) -> Fut + Clone + Send + Sync + 'static,
252 Fut: Future<Output = Res> + Send + 'static,
253 Res: IntoResponse + ResponseModifier,
254 T1: FromRequest + OperationModifier + Send + 'static,
255 T2: FromRequest + OperationModifier + Send + 'static,
256 T3: FromRequest + OperationModifier + Send + 'static,
257 T4: FromRequest + OperationModifier + Send + 'static,
258{
259 type Future = Pin<Box<dyn Future<Output = Response> + Send>>;
260
261 fn call(self, mut req: Request) -> Self::Future {
262 Box::pin(async move {
263 let t1 = match T1::from_request(&mut req).await {
264 Ok(v) => v,
265 Err(e) => return e.into_response(),
266 };
267 let t2 = match T2::from_request(&mut req).await {
268 Ok(v) => v,
269 Err(e) => return e.into_response(),
270 };
271 let t3 = match T3::from_request(&mut req).await {
272 Ok(v) => v,
273 Err(e) => return e.into_response(),
274 };
275 let t4 = match T4::from_request(&mut req).await {
276 Ok(v) => v,
277 Err(e) => return e.into_response(),
278 };
279 self(t1, t2, t3, t4).await.into_response()
280 })
281 }
282
283 fn update_operation(op: &mut Operation) {
284 T1::update_operation(op);
285 T2::update_operation(op);
286 T3::update_operation(op);
287 T4::update_operation(op);
288 Res::update_response(op);
289 }
290
291 fn register_components(spec: &mut rustapi_openapi::OpenApiSpec) {
292 T1::register_components(spec);
293 T2::register_components(spec);
294 T3::register_components(spec);
295 T4::register_components(spec);
296 Res::register_components(spec);
297 }
298}
299
300impl<F, Fut, Res, T1, T2, T3, T4, T5> Handler<(T1, T2, T3, T4, T5)> for F
302where
303 F: FnOnce(T1, T2, T3, T4, T5) -> Fut + Clone + Send + Sync + 'static,
304 Fut: Future<Output = Res> + Send + 'static,
305 Res: IntoResponse + ResponseModifier,
306 T1: FromRequest + OperationModifier + Send + 'static,
307 T2: FromRequest + OperationModifier + Send + 'static,
308 T3: FromRequest + OperationModifier + Send + 'static,
309 T4: FromRequest + OperationModifier + Send + 'static,
310 T5: FromRequest + OperationModifier + Send + 'static,
311{
312 type Future = Pin<Box<dyn Future<Output = Response> + Send>>;
313
314 fn call(self, mut req: Request) -> Self::Future {
315 Box::pin(async move {
316 let t1 = match T1::from_request(&mut req).await {
317 Ok(v) => v,
318 Err(e) => return e.into_response(),
319 };
320 let t2 = match T2::from_request(&mut req).await {
321 Ok(v) => v,
322 Err(e) => return e.into_response(),
323 };
324 let t3 = match T3::from_request(&mut req).await {
325 Ok(v) => v,
326 Err(e) => return e.into_response(),
327 };
328 let t4 = match T4::from_request(&mut req).await {
329 Ok(v) => v,
330 Err(e) => return e.into_response(),
331 };
332 let t5 = match T5::from_request(&mut req).await {
333 Ok(v) => v,
334 Err(e) => return e.into_response(),
335 };
336 self(t1, t2, t3, t4, t5).await.into_response()
337 })
338 }
339
340 fn update_operation(op: &mut Operation) {
341 T1::update_operation(op);
342 T2::update_operation(op);
343 T3::update_operation(op);
344 T4::update_operation(op);
345 T5::update_operation(op);
346 Res::update_response(op);
347 }
348
349 fn register_components(spec: &mut rustapi_openapi::OpenApiSpec) {
350 T1::register_components(spec);
351 T2::register_components(spec);
352 T3::register_components(spec);
353 T4::register_components(spec);
354 T5::register_components(spec);
355 Res::register_components(spec);
356 }
357}
358
359pub(crate) type BoxedHandler =
361 std::sync::Arc<dyn Fn(Request) -> Pin<Box<dyn Future<Output = Response> + Send>> + Send + Sync>;
362
363pub(crate) fn into_boxed_handler<H, T>(handler: H) -> BoxedHandler
365where
366 H: Handler<T>,
367 T: 'static,
368{
369 std::sync::Arc::new(move |req| {
370 let handler = handler.clone();
371 Box::pin(async move { handler.call(req).await })
372 })
373}
374
375pub trait RouteHandler<T>: Handler<T> {
380 const PATH: &'static str;
382 const METHOD: &'static str;
384}
385
386pub struct Route {
388 pub(crate) path: &'static str,
389 pub(crate) method: &'static str,
390 pub(crate) handler: BoxedHandler,
391 pub(crate) operation: Operation,
392 pub(crate) component_registrar: fn(&mut rustapi_openapi::OpenApiSpec),
393 pub(crate) param_schemas: std::collections::BTreeMap<String, String>,
396 pub(crate) error_responses: Vec<(u16, String)>,
398}
399
400impl Route {
401 pub fn new<H, T>(path: &'static str, method: &'static str, handler: H) -> Self
403 where
404 H: Handler<T>,
405 T: 'static,
406 {
407 let mut operation = Operation::new();
408 H::update_operation(&mut operation);
409
410 Self {
411 path,
412 method,
413 handler: into_boxed_handler(handler),
414 operation,
415 component_registrar: <H as Handler<T>>::register_components,
416 param_schemas: std::collections::BTreeMap::new(),
417 error_responses: Vec::new(),
418 }
419 }
420 pub fn summary(mut self, summary: impl Into<String>) -> Self {
422 self.operation = self.operation.summary(summary);
423 self
424 }
425
426 pub fn description(mut self, description: impl Into<String>) -> Self {
428 self.operation = self.operation.description(description);
429 self
430 }
431
432 pub fn tag(mut self, tag: impl Into<String>) -> Self {
434 self.operation.tags.push(tag.into());
435 self
436 }
437
438 pub fn mcp(mut self, meta: rustapi_openapi::McpOperation) -> Self {
441 self.operation = self.operation.mcp(meta);
442 self
443 }
444
445 pub fn path(&self) -> &str {
447 self.path
448 }
449
450 pub fn method(&self) -> &str {
452 self.method
453 }
454
455 pub fn param(mut self, name: impl Into<String>, schema_type: impl Into<String>) -> Self {
479 self.param_schemas.insert(name.into(), schema_type.into());
480 self
481 }
482
483 pub fn param_schemas(&self) -> &std::collections::BTreeMap<String, String> {
485 &self.param_schemas
486 }
487
488 pub fn error_response(mut self, status: u16, description: impl Into<String>) -> Self {
506 let desc = description.into();
507 self.error_responses.push((status, desc.clone()));
508
509 let mut content = std::collections::BTreeMap::new();
511 content.insert(
512 "application/json".to_string(),
513 rustapi_openapi::MediaType {
514 schema: Some(rustapi_openapi::SchemaRef::Ref {
515 reference: "#/components/schemas/ErrorSchema".to_string(),
516 }),
517 example: None,
518 },
519 );
520
521 self.operation.responses.insert(
522 status.to_string(),
523 rustapi_openapi::ResponseSpec {
524 description: desc,
525 content,
526 headers: std::collections::BTreeMap::new(),
527 },
528 );
529
530 self
531 }
532
533 pub fn error_responses(&self) -> &[(u16, String)] {
535 &self.error_responses
536 }
537}
538
539#[macro_export]
541macro_rules! route {
542 ($handler:ident) => {{
543 $crate::Route::new($handler::PATH, $handler::METHOD, $handler)
544 }};
545}
546
547pub fn get_route<H, T>(path: &'static str, handler: H) -> Route
549where
550 H: Handler<T>,
551 T: 'static,
552{
553 Route::new(path, "GET", handler)
554}
555
556pub fn post_route<H, T>(path: &'static str, handler: H) -> Route
558where
559 H: Handler<T>,
560 T: 'static,
561{
562 Route::new(path, "POST", handler)
563}
564
565pub fn put_route<H, T>(path: &'static str, handler: H) -> Route
567where
568 H: Handler<T>,
569 T: 'static,
570{
571 Route::new(path, "PUT", handler)
572}
573
574pub fn patch_route<H, T>(path: &'static str, handler: H) -> Route
576where
577 H: Handler<T>,
578 T: 'static,
579{
580 Route::new(path, "PATCH", handler)
581}
582
583pub fn delete_route<H, T>(path: &'static str, handler: H) -> Route
585where
586 H: Handler<T>,
587 T: 'static,
588{
589 Route::new(path, "DELETE", handler)
590}