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}