reifydb_sub_server_http/
handlers.rs1use axum::{
12 Json,
13 extract::State,
14 http::{HeaderMap, StatusCode},
15 response::IntoResponse,
16};
17use reifydb_sub_server::{
18 AppState, ResponseFrame, convert_frames, execute_command, execute_query, extract_identity_from_api_key,
19 extract_identity_from_auth_header,
20};
21use reifydb_type::Params;
22use serde::{Deserialize, Serialize};
23
24use crate::error::AppError;
25
26#[derive(Debug, Deserialize)]
28pub struct StatementRequest {
29 pub statements: Vec<String>,
31 #[serde(default)]
33 pub params: Option<Params>,
34}
35
36#[derive(Debug, Serialize)]
38pub struct QueryResponse {
39 pub frames: Vec<ResponseFrame>,
41}
42
43#[derive(Debug, Serialize)]
45pub struct HealthResponse {
46 pub status: &'static str,
47}
48
49pub async fn health() -> impl IntoResponse {
60 (
61 StatusCode::OK,
62 Json(HealthResponse {
63 status: "ok",
64 }),
65 )
66}
67
68pub async fn handle_query(
93 State(state): State<AppState>,
94 headers: HeaderMap,
95 Json(request): Json<StatementRequest>,
96) -> Result<Json<QueryResponse>, AppError> {
97 let identity = extract_identity(&headers)?;
99
100 let query = request.statements.join("; ");
102
103 let params = request.params.unwrap_or(Params::None);
105
106 let frames = execute_query(state.engine_clone(), query, identity, params, state.query_timeout()).await?;
108
109 Ok(Json(QueryResponse {
110 frames: convert_frames(frames),
111 }))
112}
113
114pub async fn handle_command(
141 State(state): State<AppState>,
142 headers: HeaderMap,
143 Json(request): Json<StatementRequest>,
144) -> Result<Json<QueryResponse>, AppError> {
145 let identity = extract_identity(&headers)?;
147
148 let params = request.params.unwrap_or(Params::None);
150
151 let frames = execute_command(state.engine_clone(), request.statements, identity, params, state.query_timeout())
153 .await?;
154
155 Ok(Json(QueryResponse {
156 frames: convert_frames(frames),
157 }))
158}
159
160fn extract_identity(headers: &HeaderMap) -> Result<reifydb_core::interface::Identity, AppError> {
166 if let Some(auth_header) = headers.get("authorization") {
168 let auth_str = auth_header
169 .to_str()
170 .map_err(|_| AppError::Auth(reifydb_sub_server::AuthError::InvalidHeader))?;
171
172 return extract_identity_from_auth_header(auth_str).map_err(AppError::Auth);
173 }
174
175 if let Some(api_key) = headers.get("x-api-key") {
177 let key = api_key.to_str().map_err(|_| AppError::Auth(reifydb_sub_server::AuthError::InvalidHeader))?;
178
179 return extract_identity_from_api_key(key).map_err(AppError::Auth);
180 }
181
182 Err(AppError::Auth(reifydb_sub_server::AuthError::MissingCredentials))
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189
190 #[test]
191 fn test_statement_request_deserialization() {
192 let json = r#"{"statements": ["SELECT 1"]}"#;
193 let request: StatementRequest = serde_json::from_str(json).unwrap();
194 assert_eq!(request.statements, vec!["SELECT 1"]);
195 assert!(request.params.is_none());
196 }
197
198 #[test]
199 fn test_query_response_serialization() {
200 let response = QueryResponse {
201 frames: Vec::new(),
202 };
203 let json = serde_json::to_string(&response).unwrap();
204 assert!(json.contains("frames"));
205 }
206
207 #[test]
208 fn test_health_response_serialization() {
209 let response = HealthResponse {
210 status: "ok",
211 };
212 let json = serde_json::to_string(&response).unwrap();
213 assert_eq!(json, r#"{"status":"ok"}"#);
214 }
215}