this/server/exposure/rest/
mod.rs

1//! REST API exposure for the framework
2//!
3//! This module provides REST-specific routing and handlers.
4//! It is isolated from the core framework logic and can be replaced
5//! or extended with other protocols (GraphQL, gRPC, etc.)
6//!
7//! The REST exposure consumes a `ServerHost` and produces an Axum `Router`.
8
9use super::super::host::ServerHost;
10use crate::links::handlers::AppState;
11use crate::server::router::build_link_routes;
12use anyhow::Result;
13use axum::{Json, Router, routing::get};
14use serde_json::{Value, json};
15use std::sync::Arc;
16
17/// REST API exposure implementation
18///
19/// This struct encapsulates all REST-specific logic for exposing the API.
20/// It is completely separate from the framework core and can be replaced
21/// with other exposure types (GraphQL, gRPC, etc.).
22pub struct RestExposure;
23
24impl RestExposure {
25    /// Build the REST router from a host
26    ///
27    /// This method takes a `ServerHost` (which is transport-agnostic) and
28    /// builds an Axum router with all REST endpoints.
29    ///
30    /// # Arguments
31    ///
32    /// * `host` - The server host containing all framework state
33    /// * `custom_routes` - Additional custom routes to merge
34    ///
35    /// # Returns
36    ///
37    /// Returns a fully configured Axum router with:
38    /// - Health check routes
39    /// - Entity CRUD routes
40    /// - Link routes
41    /// - Custom routes
42    pub fn build_router(host: Arc<ServerHost>, custom_routes: Vec<Router>) -> Result<Router> {
43        // Create link app state from host
44        let link_state = AppState {
45            link_service: host.link_service.clone(),
46            config: host.config.clone(),
47            registry: host.registry.clone(),
48            entity_fetchers: host.entity_fetchers.clone(),
49            entity_creators: host.entity_creators.clone(),
50        };
51
52        // Build all routes
53        let health_routes = Self::health_routes();
54        let entity_routes = host.entity_registry.build_routes();
55        let link_routes = build_link_routes(link_state.clone());
56
57        // Merge everything
58        let mut app = health_routes.merge(entity_routes);
59
60        for custom_router in custom_routes {
61            app = app.merge(custom_router);
62        }
63
64        app = app.merge(link_routes);
65
66        Ok(app)
67    }
68
69    /// Build health check routes
70    fn health_routes() -> Router {
71        Router::new()
72            .route("/health", get(Self::health_check))
73            .route("/healthz", get(Self::health_check))
74    }
75
76    /// Health check endpoint handler
77    async fn health_check() -> Json<Value> {
78        Json(json!({
79            "status": "ok",
80            "service": "this-rs"
81        }))
82    }
83}