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 event_bus: host.event_bus.clone(),
51 };
52
53 // Build all routes
54 let health_routes = Self::health_routes();
55 let entity_routes = host.entity_registry.build_routes();
56 let link_routes = build_link_routes(link_state.clone());
57
58 // Merge everything
59 let mut app = health_routes.merge(entity_routes);
60
61 for custom_router in custom_routes {
62 app = app.merge(custom_router);
63 }
64
65 app = app.merge(link_routes);
66
67 Ok(app)
68 }
69
70 /// Build health check routes
71 fn health_routes() -> Router {
72 Router::new()
73 .route("/health", get(Self::health_check))
74 .route("/healthz", get(Self::health_check))
75 }
76
77 /// Health check endpoint handler
78 async fn health_check() -> Json<Value> {
79 Json(json!({
80 "status": "ok",
81 "service": "this-rs"
82 }))
83 }
84}