vibe_graph_api/routes/
mod.rs

1//! API route handlers.
2
3mod git;
4mod graph;
5mod health;
6pub mod ops;
7
8use std::sync::Arc;
9
10use axum::{
11    routing::{delete, get, post},
12    Router,
13};
14use tower_http::cors::{Any, CorsLayer};
15use tower_http::trace::{DefaultMakeSpan, DefaultOnResponse, TraceLayer};
16use tracing::Level;
17use vibe_graph_ops::OpsContext;
18
19use crate::types::ApiState;
20use crate::ws::ws_handler;
21use ops::OpsState;
22
23/// Create the API router with all endpoints.
24pub fn create_api_router(state: Arc<ApiState>) -> Router {
25    let cors = CorsLayer::new()
26        .allow_origin(Any)
27        .allow_methods(Any)
28        .allow_headers(Any);
29
30    Router::new()
31        // Health
32        .route("/health", get(health::health_handler))
33        // Graph endpoints
34        .route("/graph", get(graph::graph_handler))
35        .route("/graph/nodes", get(graph::nodes_handler))
36        .route("/graph/edges", get(graph::edges_handler))
37        .route("/graph/metadata", get(graph::metadata_handler))
38        // Git endpoints
39        .route("/git/changes", get(git::changes_handler))
40        // WebSocket
41        .route("/ws", get(ws_handler))
42        // Request tracing (enable with RUST_LOG=tower_http=info or higher)
43        .layer(
44            TraceLayer::new_for_http()
45                .make_span_with(
46                    DefaultMakeSpan::new()
47                        .level(Level::INFO)
48                        .include_headers(false),
49                )
50                .on_response(DefaultOnResponse::new().level(Level::INFO)),
51        )
52        .layer(cors)
53        .with_state(state)
54}
55
56/// Create the operations router with all ops endpoints.
57///
58/// This router provides REST access to all vibe-graph operations.
59/// Mount at `/api/ops` for full API access.
60pub fn create_ops_router(ctx: OpsContext) -> Router {
61    let state = Arc::new(OpsState { ctx });
62
63    let cors = CorsLayer::new()
64        .allow_origin(Any)
65        .allow_methods(Any)
66        .allow_headers(Any);
67
68    Router::new()
69        // Sync operations
70        .route("/sync", post(ops::sync_handler))
71        .route("/sync", get(ops::sync_query_handler))
72        // Graph operations
73        .route("/graph", post(ops::graph_handler))
74        .route("/graph", get(ops::graph_query_handler))
75        // Status
76        .route("/status", get(ops::status_handler))
77        // Load
78        .route("/load", get(ops::load_handler))
79        // Clean
80        .route("/clean", delete(ops::clean_handler))
81        // Git changes
82        .route("/git-changes", get(ops::git_changes_handler))
83        // Request tracing
84        .layer(
85            TraceLayer::new_for_http()
86                .make_span_with(
87                    DefaultMakeSpan::new()
88                        .level(Level::INFO)
89                        .include_headers(false),
90                )
91                .on_response(DefaultOnResponse::new().level(Level::INFO)),
92        )
93        .layer(cors)
94        .with_state(state)
95}
96
97/// Create a combined API router with both graph/ws and ops endpoints.
98///
99/// This creates a router that serves:
100/// - `/ops/*` - Operations API (sync, graph build, status, etc.)
101/// - `/health`, `/graph/*`, `/git/*`, `/ws` - Graph visualization API
102pub fn create_full_api_router(api_state: Arc<ApiState>, ops_ctx: OpsContext) -> Router {
103    let cors = CorsLayer::new()
104        .allow_origin(Any)
105        .allow_methods(Any)
106        .allow_headers(Any);
107
108    // Create the ops router (already has state applied, becomes Router<()>)
109    let ops_router = create_ops_router(ops_ctx);
110
111    // Create the visualization API router with its state
112    let viz_router = Router::new()
113        .route("/health", get(health::health_handler))
114        .route("/graph", get(graph::graph_handler))
115        .route("/graph/nodes", get(graph::nodes_handler))
116        .route("/graph/edges", get(graph::edges_handler))
117        .route("/graph/metadata", get(graph::metadata_handler))
118        .route("/git/changes", get(git::changes_handler))
119        .route("/ws", get(ws_handler))
120        .with_state(api_state);
121
122    // Merge both routers
123    Router::new()
124        .nest("/ops", ops_router)
125        .merge(viz_router)
126        .layer(
127            TraceLayer::new_for_http()
128                .make_span_with(
129                    DefaultMakeSpan::new()
130                        .level(Level::INFO)
131                        .include_headers(false),
132                )
133                .on_response(DefaultOnResponse::new().level(Level::INFO)),
134        )
135        .layer(cors)
136}