Skip to main content

nestrs_core/
route_registry.rs

1use std::sync::{OnceLock, RwLock};
2
3/// One HTTP response line for OpenAPI generation (per route).
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub struct OpenApiResponseDesc {
6    pub status: u16,
7    pub description: &'static str,
8}
9
10/// Optional per-route OpenAPI metadata (from `#[openapi(...)]` / `impl_routes!` `openapi` clause).
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub struct OpenApiRouteSpec {
13    pub summary: Option<&'static str>,
14    pub tag: Option<&'static str>,
15    pub responses: &'static [OpenApiResponseDesc],
16}
17
18#[derive(Debug, Clone, PartialEq, Eq, Hash)]
19pub struct RouteInfo {
20    pub method: &'static str,
21    pub path: &'static str,
22    pub handler: &'static str,
23    pub openapi: Option<&'static OpenApiRouteSpec>,
24}
25
26fn store() -> &'static RwLock<Vec<RouteInfo>> {
27    static STORE: OnceLock<RwLock<Vec<RouteInfo>>> = OnceLock::new();
28    STORE.get_or_init(|| RwLock::new(Vec::new()))
29}
30
31/// Global route registry (used by OpenAPI generation and diagnostics).
32pub struct RouteRegistry;
33
34impl RouteRegistry {
35    /// Register a route with no OpenAPI overrides (defaults: inferred summary/tags, `200` only).
36    pub fn register(method: &'static str, path: &'static str, handler: &'static str) {
37        Self::register_spec(method, path, handler, None);
38    }
39
40    /// Register a route; `openapi` may point at a leaked or `const` [`OpenApiRouteSpec`].
41    pub fn register_spec(
42        method: &'static str,
43        path: &'static str,
44        handler: &'static str,
45        openapi: Option<&'static OpenApiRouteSpec>,
46    ) {
47        let mut guard = store().write().expect("route registry lock poisoned");
48        guard.push(RouteInfo {
49            method,
50            path,
51            handler,
52            openapi,
53        });
54    }
55
56    pub fn list() -> Vec<RouteInfo> {
57        let guard = store().read().expect("route registry lock poisoned");
58        guard.clone()
59    }
60
61    /// Clears all registered HTTP routes in this process.
62    ///
63    /// **Available only with the `test-hooks` feature.** Intended for integration tests that share
64    /// a process with other tests; production applications must never call this (routes would
65    /// disappear from OpenAPI / diagnostics).
66    #[cfg(feature = "test-hooks")]
67    pub fn clear_for_tests() {
68        let mut guard = store().write().expect("route registry lock poisoned");
69        guard.clear();
70    }
71}