Menyeragamkan format kode sesuai rustfmt (126 file). Sebelumnya lefthook pre-commit 'cargo fmt --check' akan gagal pada commit apa pun.
114 lines
3.9 KiB
Rust
114 lines
3.9 KiB
Rust
//! # Zesdex REST API — Axum HTTP server
|
|
//!
|
|
//! Provides RESTful endpoints for the Zesdex application, enabling
|
|
//! web clients, mobile apps, and third-party integrations.
|
|
//!
|
|
//! ## Architecture
|
|
//!
|
|
//! ```text
|
|
//! src/
|
|
//! ├── lib.rs — Module declarations, re-exports, router builder
|
|
//! ├── state.rs — ApiState with concrete service implementations
|
|
//! ├── error.rs — ApiError enum + IntoResponse
|
|
//! ├── dto/ — Request/response DTOs (serde)
|
|
//! ├── handlers/ — Axum route handlers
|
|
//! └── middleware/ — Tower layers (JWT auth, etc.)
|
|
//! ```
|
|
//!
|
|
//! ## Flow
|
|
//!
|
|
//! 1. `build_router()` constructs an Axum `Router` with all routes nested.
|
|
//! 2. Each handler receives `State<Arc<ApiState>>` or direct extractors.
|
|
//! 3. Handlers delegate to application-layer service implementations.
|
|
//! 4. Domain/infrastructure errors are mapped to `ApiError` → HTTP status codes.
|
|
|
|
pub mod dto;
|
|
pub mod error;
|
|
pub mod handlers;
|
|
pub mod middleware;
|
|
pub mod state;
|
|
|
|
pub use error::ApiError;
|
|
pub use state::ApiState;
|
|
|
|
use axum::Router;
|
|
use std::sync::Arc;
|
|
use tower_http::cors::CorsLayer;
|
|
|
|
/// Build the API router with all routes registered.
|
|
///
|
|
/// Flow: create CORS layer → build sub-routers for each resource → nest
|
|
/// them under `/api/v1` → attach shared state → return.
|
|
///
|
|
/// ## Arguments
|
|
/// * `state` — shared application state (wrapped in `Arc` for clone-free sharing)
|
|
///
|
|
/// ## Example
|
|
/// ```ignore
|
|
/// let state = ApiState::new("/path/to/data");
|
|
/// let app = build_router(state);
|
|
/// let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
|
/// axum::serve(listener, app).await.unwrap();
|
|
/// ```
|
|
pub fn build_router(state: ApiState) -> Router {
|
|
let shared_state: Arc<ApiState> = Arc::new(state);
|
|
|
|
// CORS layer — permissive for local daemon / development use
|
|
let cors = CorsLayer::permissive();
|
|
|
|
// JWT auth middleware — protects session/chat routes.
|
|
// Auth (login/register/refresh) and health endpoints stay public.
|
|
let jwt_auth = middleware::auth::JwtAuthLayer::new(shared_state.clone());
|
|
|
|
// Combine all sub-routers under a versioned prefix
|
|
Router::new()
|
|
.nest("/api/v1/auth", auth_router())
|
|
.nest("/api/v1/health", health_router())
|
|
.nest("/api/v1", protected_router().layer(jwt_auth))
|
|
.layer(cors)
|
|
.with_state(shared_state)
|
|
}
|
|
|
|
/// Auth + health sub-routers — publicly accessible (no JWT required).
|
|
fn auth_router() -> Router<Arc<ApiState>> {
|
|
handlers::auth::router()
|
|
}
|
|
|
|
fn health_router() -> Router<Arc<ApiState>> {
|
|
Router::new().route("/", axum::routing::get(handlers::health::health))
|
|
}
|
|
|
|
/// Protected sub-router — sessions + chat, guarded by JWT auth layer.
|
|
fn protected_router() -> Router<Arc<ApiState>> {
|
|
use handlers::{chat, conversations, sessions};
|
|
|
|
// Sessions router combines session CRUD + nested conversations
|
|
let sessions_router = Router::new()
|
|
.route("/", axum::routing::get(sessions::list_sessions_handler))
|
|
.route("/", axum::routing::post(sessions::create_session_handler))
|
|
.route(
|
|
"/{id}",
|
|
axum::routing::delete(sessions::delete_session_handler),
|
|
)
|
|
// Conversations are sub-resources of sessions
|
|
.route(
|
|
"/{id}/conversations",
|
|
axum::routing::get(conversations::get_conversation_handler),
|
|
)
|
|
.route(
|
|
"/{id}/conversations",
|
|
axum::routing::post(conversations::add_message_handler),
|
|
)
|
|
.route(
|
|
"/{id}/conversations/{cid}",
|
|
axum::routing::delete(conversations::delete_message_handler),
|
|
);
|
|
|
|
Router::new()
|
|
.nest("/sessions", sessions_router)
|
|
.nest("/chat", chat::router())
|
|
}
|
|
|
|
// Re-export commonly used types at the crate root for ergonomic access.
|
|
pub use axum::http::StatusCode;
|