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 auth::{AuthError, extract_identity_from_api_key, extract_identity_from_auth_header},
19 execute::{execute_admin, execute_command, execute_query},
20 response::{ResponseFrame, convert_frames},
21 state::AppState,
22};
23use reifydb_type::params::Params;
24use serde::{Deserialize, Serialize};
25
26use crate::error::AppError;
27
28#[derive(Debug, Deserialize)]
30pub struct StatementRequest {
31 pub statements: Vec<String>,
33 #[serde(default)]
35 pub params: Option<Params>,
36}
37
38#[derive(Debug, Serialize)]
40pub struct QueryResponse {
41 pub frames: Vec<ResponseFrame>,
43}
44
45#[derive(Debug, Serialize)]
47pub struct HealthResponse {
48 pub status: &'static str,
49}
50
51pub async fn health() -> impl IntoResponse {
62 (
63 StatusCode::OK,
64 Json(HealthResponse {
65 status: "ok",
66 }),
67 )
68}
69
70pub async fn handle_query(
95 State(state): State<AppState>,
96 headers: HeaderMap,
97 Json(request): Json<StatementRequest>,
98) -> Result<Json<QueryResponse>, AppError> {
99 let identity = extract_identity(&headers)?;
101
102 let query = request.statements.join("; ");
104
105 let params = request.params.unwrap_or(Params::None);
107
108 let frames = execute_query(
110 state.actor_system(),
111 state.engine_clone(),
112 query,
113 identity,
114 params,
115 state.query_timeout(),
116 )
117 .await?;
118
119 Ok(Json(QueryResponse {
120 frames: convert_frames(frames),
121 }))
122}
123
124pub async fn handle_admin(
135 State(state): State<AppState>,
136 headers: HeaderMap,
137 Json(request): Json<StatementRequest>,
138) -> Result<Json<QueryResponse>, AppError> {
139 let identity = extract_identity(&headers)?;
141
142 let params = request.params.unwrap_or(Params::None);
144
145 let frames = execute_admin(
147 state.actor_system(),
148 state.engine_clone(),
149 request.statements,
150 identity,
151 params,
152 state.query_timeout(),
153 )
154 .await?;
155
156 Ok(Json(QueryResponse {
157 frames: convert_frames(frames),
158 }))
159}
160
161pub async fn handle_command(
188 State(state): State<AppState>,
189 headers: HeaderMap,
190 Json(request): Json<StatementRequest>,
191) -> Result<Json<QueryResponse>, AppError> {
192 let identity = extract_identity(&headers)?;
194
195 let params = request.params.unwrap_or(Params::None);
197
198 let frames = execute_command(
200 state.actor_system(),
201 state.engine_clone(),
202 request.statements,
203 identity,
204 params,
205 state.query_timeout(),
206 )
207 .await?;
208
209 Ok(Json(QueryResponse {
210 frames: convert_frames(frames),
211 }))
212}
213
214fn extract_identity(headers: &HeaderMap) -> Result<reifydb_core::interface::auth::Identity, AppError> {
220 if let Some(auth_header) = headers.get("authorization") {
222 let auth_str = auth_header.to_str().map_err(|_| AppError::Auth(AuthError::InvalidHeader))?;
223
224 return extract_identity_from_auth_header(auth_str).map_err(AppError::Auth);
225 }
226
227 if let Some(api_key) = headers.get("x-api-key") {
229 let key = api_key.to_str().map_err(|_| AppError::Auth(AuthError::InvalidHeader))?;
230
231 return extract_identity_from_api_key(key).map_err(AppError::Auth);
232 }
233
234 Err(AppError::Auth(AuthError::MissingCredentials))
236}
237
238#[cfg(test)]
239pub mod tests {
240 use super::*;
241
242 #[test]
243 fn test_statement_request_deserialization() {
244 let json = r#"{"statements": ["SELECT 1"]}"#;
245 let request: StatementRequest = serde_json::from_str(json).unwrap();
246 assert_eq!(request.statements, vec!["SELECT 1"]);
247 assert!(request.params.is_none());
248 }
249
250 #[test]
251 fn test_query_response_serialization() {
252 let response = QueryResponse {
253 frames: Vec::new(),
254 };
255 let json = serde_json::to_string(&response).unwrap();
256 assert!(json.contains("frames"));
257 }
258
259 #[test]
260 fn test_health_response_serialization() {
261 let response = HealthResponse {
262 status: "ok",
263 };
264 let json = serde_json::to_string(&response).unwrap();
265 assert_eq!(json, r#"{"status":"ok"}"#);
266 }
267}