scouter_server/api/
handler.rs

1use crate::api::schema::{DriftRecordRequest, ServiceDriftRequest};
2use crate::sql::postgres::TimeInterval;
3use crate::sql::schema::{DriftRecord, MonitorProfile};
4use axum::{
5    extract::{Query, State},
6    http::StatusCode,
7    response::IntoResponse,
8    Json,
9};
10use serde_json::json;
11use std::sync::Arc;
12use tracing::{error, info};
13
14use crate::api::route::AppState;
15
16pub async fn health_check() -> impl IntoResponse {
17    info!("Health check endpoint is called");
18
19    const MESSAGE: &str = "Alive";
20
21    let json_response = serde_json::json!({
22        "status": "success",
23        "message": MESSAGE
24    });
25
26    Json(json_response)
27}
28
29pub async fn get_drift(
30    State(data): State<Arc<AppState>>,
31    params: Query<ServiceDriftRequest>,
32) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
33    // validate time window
34
35    let time_interval = TimeInterval::from_string(&params.time_window).to_minutes();
36
37    let query_result = &data
38        .db
39        .get_binned_drift_records(
40            &params.name,
41            &params.repository,
42            &params.version,
43            &params.max_data_points,
44            &time_interval,
45        )
46        .await;
47
48    match query_result {
49        Ok(result) => {
50            let json_response = serde_json::json!({
51                "status": "success",
52                "data": result
53            });
54            Ok(Json(json_response))
55        }
56        Err(e) => {
57            error!("Failed to query drift records: {:?}", e);
58            let json_response = json!({
59                "status": "error",
60                "message": format!("{:?}", e)
61            });
62            Err((StatusCode::INTERNAL_SERVER_ERROR, Json(json_response)))
63        }
64    }
65}
66
67pub async fn insert_drift(
68    State(data): State<Arc<AppState>>,
69    Json(body): Json<DriftRecordRequest>,
70) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
71    // set default if missing
72    let record = DriftRecord {
73        created_at: body
74            .created_at
75            .unwrap_or_else(|| chrono::Utc::now().naive_utc()),
76        name: body.name.clone(),
77        repository: body.repository.clone(),
78        feature: body.feature.clone(),
79        value: body.value,
80        version: body.version.clone(),
81    };
82
83    let query_result = &data.db.insert_drift_record(&record).await;
84
85    match query_result {
86        Ok(_) => {
87            let json_response = json!({
88                "status": "success",
89                "message": "Record inserted successfully"
90            });
91            Ok(Json(json_response))
92        }
93        Err(e) => {
94            error!("Failed to insert drift record: {:?}", e);
95            let json_response = json!({
96                "status": "error",
97                "message": format!("{:?}", e)
98            });
99            Err((StatusCode::INTERNAL_SERVER_ERROR, Json(json_response)))
100        }
101    }
102}
103
104pub async fn insert_drift_profile(
105    State(data): State<Arc<AppState>>,
106    Json(body): Json<MonitorProfile>,
107) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
108    let query_result = &data.db.insert_drift_profile(&body).await;
109
110    match query_result {
111        Ok(_) => {
112            let json_response = json!({
113                "status": "success",
114                "message": "Monitor profile inserted successfully"
115            });
116            Ok(Json(json_response))
117        }
118        Err(e) => {
119            error!("Failed to insert monitor profile: {:?}", e);
120            let json_response = json!({
121                "status": "error",
122                "message": format!("{:?}", e)
123            });
124            Err((StatusCode::INTERNAL_SERVER_ERROR, Json(json_response)))
125        }
126    }
127}