Skip to main content

remem/api/
server.rs

1use axum::{
2    middleware,
3    routing::{get, post},
4    Extension, Router,
5};
6
7use super::auth::{ensure_api_token, require_api_token};
8use super::handlers::{
9    handle_approve_candidate, handle_archive_memory, handle_blocked_candidates,
10    handle_candidate_detail, handle_capabilities, handle_edit_candidate, handle_event_detail,
11    handle_get_memory, handle_graph, handle_health, handle_list_candidates, handle_list_events,
12    handle_list_memories, handle_list_observations, handle_list_sessions, handle_list_tasks,
13    handle_list_workstreams, handle_memory_detail, handle_observation_detail,
14    handle_reject_candidate, handle_restore_memory, handle_safe_approve_candidate,
15    handle_safe_edit_candidate, handle_safe_reject_candidate, handle_save_memory, handle_search,
16    handle_session_detail, handle_stats, handle_status, handle_task_detail, handle_user_recall,
17    handle_workstream_detail,
18};
19use super::types::{DbState, StatusCache};
20
21pub fn build_router(_port: u16) -> Router<DbState> {
22    Router::new()
23        .route("/api/v1/health", get(handle_health))
24        .route("/api/v1/capabilities", get(handle_capabilities))
25        .route("/api/v1/search", get(handle_search))
26        .route("/api/v1/memory", get(handle_get_memory))
27        .route(
28            "/api/v1/memories",
29            get(handle_list_memories).post(handle_save_memory),
30        )
31        .route("/api/v1/user/recall", post(handle_user_recall))
32        .route("/api/v1/status", get(handle_status))
33        .route("/api/v1/memories/list", get(handle_list_memories))
34        .route("/api/v1/memories/{id}", get(handle_memory_detail))
35        .route("/api/v1/memories/{id}/archive", post(handle_archive_memory))
36        .route("/api/v1/memories/{id}/restore", post(handle_restore_memory))
37        .route("/api/v1/candidates", get(handle_list_candidates))
38        .route("/api/v1/candidates/blocked", get(handle_blocked_candidates))
39        .route("/api/v1/candidates/{id}", get(handle_candidate_detail))
40        .route(
41            "/api/v1/candidates/{id}/approve",
42            post(handle_approve_candidate),
43        )
44        .route(
45            "/api/v1/candidates/{id}/reject",
46            post(handle_reject_candidate),
47        )
48        .route("/api/v1/candidates/{id}/edit", post(handle_edit_candidate))
49        .route(
50            "/api/v1/candidates/{id}/review/approve",
51            post(handle_safe_approve_candidate),
52        )
53        .route(
54            "/api/v1/candidates/{id}/review/reject",
55            post(handle_safe_reject_candidate),
56        )
57        .route(
58            "/api/v1/candidates/{id}/review/edit",
59            post(handle_safe_edit_candidate),
60        )
61        .route("/api/v1/observations", get(handle_list_observations))
62        .route("/api/v1/observations/{id}", get(handle_observation_detail))
63        .route("/api/v1/sessions", get(handle_list_sessions))
64        .route("/api/v1/sessions/{id}", get(handle_session_detail))
65        .route("/api/v1/workstreams", get(handle_list_workstreams))
66        .route("/api/v1/workstreams/{id}", get(handle_workstream_detail))
67        .route("/api/v1/events", get(handle_list_events))
68        .route("/api/v1/events/{id}", get(handle_event_detail))
69        .route("/api/v1/tasks", get(handle_list_tasks))
70        .route("/api/v1/tasks/{id}", get(handle_task_detail))
71        .route("/api/v1/graph", get(handle_graph))
72        .route("/api/v1/stats", get(handle_stats))
73        .route_layer(middleware::from_fn(require_api_token))
74        .layer(Extension(StatusCache::default()))
75}
76
77pub async fn run_api_server(port: u16) -> anyhow::Result<()> {
78    let token_path = ensure_api_token()?;
79    let app = build_router(port).with_state(DbState);
80    let addr = format!("127.0.0.1:{}", port);
81
82    crate::log::info("api", &format!("REST API listening on http://{}", addr));
83    println!(
84        "remem REST API v{} on http://{}",
85        env!("CARGO_PKG_VERSION"),
86        addr
87    );
88    println!(
89        "API token: Authorization: Bearer $(cat {})",
90        token_path.display()
91    );
92
93    let listener = tokio::net::TcpListener::bind(&addr).await?;
94    axum::serve(listener, app).await?;
95    Ok(())
96}