Skip to main content

serverust_core/
route.rs

1use axum::routing::MethodRouter;
2use utoipa::openapi::{HttpMethod, path::Operation};
3
4use crate::container::Container;
5
6/// Metadata de uma rota registrável no [`crate::App`].
7///
8/// O `MethodRouter` é parametrizado pelo [`Container`] (state do App) para
9/// que handlers possam extrair serviços via `State<Arc<dyn Trait>>`.
10pub struct Route {
11    pub path: &'static str,
12    pub method: HttpMethod,
13    pub method_router: MethodRouter<Container>,
14    pub operation: Operation,
15    /// Se a rota dispensa autenticação.
16    ///
17    /// Default `false` — o default deny da ADR 0009. Com autenticação
18    /// instalada, [`crate::App::route`] embrulha toda rota que **não** tenha
19    /// isto ligado com o [`crate::AuthGate`]. Ligue via [`Route::public`].
20    pub is_public: bool,
21    /// Escopos que a rota exige, para o `security` do OpenAPI.
22    ///
23    /// Preenchido pela macro `#[authorize]`. **Não é o que aplica a
24    /// exigência** — quem faz isso é o `Guard` que a macro injeta. Aqui é só
25    /// o que o documento precisa declarar, para que o botão "Authorize" do
26    /// Scalar/Swagger UI peça os escopos certos.
27    ///
28    /// Separar as duas coisas é o que permite documentar sem mexer na trait
29    /// [`crate::Guard`]; o custo é que um guard escrito à mão não aparece no
30    /// documento, por não ter como declarar o que exige.
31    pub required_scopes: &'static [&'static str],
32}
33
34impl Route {
35    pub fn new(
36        path: &'static str,
37        method: HttpMethod,
38        method_router: MethodRouter<Container>,
39        operation: Operation,
40    ) -> Self {
41        Self {
42            path,
43            method,
44            method_router,
45            operation,
46            is_public: false,
47            required_scopes: &[],
48        }
49    }
50
51    /// Marca a rota como pública: ela responde mesmo sem identidade.
52    ///
53    /// É a exceção explícita ao default deny — o equivalente do `pub` do Rust
54    /// para rotas. Marcar o que é aberto, em vez do que é protegido, é o que
55    /// torna a superfície exposta auditável por presença: `grep` encontra
56    /// marcação, nunca a falta dela.
57    ///
58    /// ```
59    /// # use serverust_core::Route;
60    /// # use axum::routing::get;
61    /// # use utoipa::openapi::{HttpMethod, path::Operation};
62    /// let route = Route::new("/health", HttpMethod::Get, get(|| async {}), Operation::new())
63    ///     .public();
64    /// assert!(route.is_public);
65    /// ```
66    pub fn public(mut self) -> Self {
67        self.is_public = true;
68        self
69    }
70
71    /// Declara os escopos que a rota exige, para o `security` do OpenAPI.
72    ///
73    /// Chamada pela macro `#[authorize]`. Chamar à mão documenta a exigência
74    /// sem aplicá-la — o que é pior do que não documentar, porque passa a
75    /// mentir. Use junto com o guard que realmente verifica.
76    pub fn scopes(mut self, scopes: &'static [&'static str]) -> Self {
77        self.required_scopes = scopes;
78        self
79    }
80}
81
82/// Implementado pelas structs geradas pelas macros `#[get]`, `#[post]`, etc.
83///
84/// Permite passar o nome do handler diretamente para `App::route(handler)`.
85pub trait IntoRoute {
86    fn into_route(self) -> Route;
87}