kotoba_server_core/
handlers.rs

1//! Common HTTP handlers
2
3use axum::{
4    response::{Json, IntoResponse},
5    http::StatusCode,
6};
7use chrono::{DateTime, Utc};
8use serde::{Deserialize, Serialize};
9
10use crate::router::HealthResponse;
11
12/// Health check handler
13pub async fn health_check() -> Json<HealthResponse> {
14    Json(HealthResponse::default())
15}
16
17/// Liveness probe handler
18pub async fn liveness() -> impl IntoResponse {
19    (StatusCode::OK, "OK")
20}
21
22/// Readiness probe handler
23pub async fn readiness() -> impl IntoResponse {
24    // TODO: Add actual readiness checks (database connections, etc.)
25    (StatusCode::OK, "OK")
26}
27
28/// 404 Not Found handler
29pub async fn not_found() -> impl IntoResponse {
30    (
31        StatusCode::NOT_FOUND,
32        Json(serde_json::json!({
33            "error": "Not Found",
34            "message": "The requested resource was not found",
35            "code": 404
36        })),
37    )
38}
39
40/// Method not allowed handler
41pub async fn method_not_allowed() -> impl IntoResponse {
42    (
43        StatusCode::METHOD_NOT_ALLOWED,
44        Json(serde_json::json!({
45            "error": "Method Not Allowed",
46            "message": "The requested method is not allowed for this resource",
47            "code": 405
48        })),
49    )
50}
51
52/// Generic error handler
53pub async fn internal_error() -> impl IntoResponse {
54    (
55        StatusCode::INTERNAL_SERVER_ERROR,
56        Json(serde_json::json!({
57            "error": "Internal Server Error",
58            "message": "An internal server error occurred",
59            "code": 500
60        })),
61    )
62}
63
64/// Health check handler struct for more complex health checks
65#[derive(Debug)]
66pub struct HealthHandler {
67    start_time: DateTime<Utc>,
68}
69
70impl HealthHandler {
71    pub fn new() -> Self {
72        Self {
73            start_time: Utc::now(),
74        }
75    }
76
77    pub async fn handle(&self) -> Json<HealthResponse> {
78        Json(HealthResponse {
79            status: "ok".to_string(),
80            timestamp: Utc::now(),
81            version: env!("CARGO_PKG_VERSION").to_string(),
82        })
83    }
84}
85
86impl Default for HealthHandler {
87    fn default() -> Self {
88        Self::new()
89    }
90}
91
92/// Not found handler with customizable response
93#[derive(Debug)]
94pub struct NotFoundHandler {
95    message: String,
96}
97
98impl NotFoundHandler {
99    pub fn new(message: impl Into<String>) -> Self {
100        Self {
101            message: message.into(),
102        }
103    }
104
105    pub fn with_message(mut self, message: impl Into<String>) -> Self {
106        self.message = message.into();
107        self
108    }
109
110    pub async fn handle(&self) -> impl IntoResponse {
111        (
112            StatusCode::NOT_FOUND,
113            Json(serde_json::json!({
114                "error": "Not Found",
115                "message": self.message,
116                "code": 404
117            })),
118        )
119    }
120}
121
122impl Default for NotFoundHandler {
123    fn default() -> Self {
124        Self::new("The requested resource was not found")
125    }
126}
127
128/// Metrics endpoint response
129#[derive(Debug, Serialize, Deserialize)]
130pub struct MetricsResponse {
131    pub uptime_seconds: i64,
132    pub total_requests: u64,
133    pub active_connections: u32,
134    pub memory_usage_mb: f64,
135}
136
137impl Default for MetricsResponse {
138    fn default() -> Self {
139        Self {
140            uptime_seconds: 0,
141            total_requests: 0,
142            active_connections: 0,
143            memory_usage_mb: 0.0,
144        }
145    }
146}
147
148/// Metrics handler (basic implementation)
149pub async fn metrics() -> Json<MetricsResponse> {
150    // TODO: Integrate with actual metrics collection
151    Json(MetricsResponse::default())
152}
153