1use axum::{
6 extract::{FromRequest, Request},
7 response::{IntoResponse, Response},
8 http::{StatusCode, HeaderMap},
9 Json,
10};
11use serde::{Deserialize, Serialize, de::DeserializeOwned};
12use std::ops::{Deref, DerefMut};
13use crate::error::{HttpError, HttpResult};
14use crate::response::{ElifResponse, IntoElifResponse};
15
16#[derive(Debug)]
18pub struct ElifJson<T>(pub T);
19
20impl<T> ElifJson<T> {
21 pub fn new(data: T) -> Self {
23 Self(data)
24 }
25
26 pub fn into_inner(self) -> T {
28 self.0
29 }
30}
31
32impl<T> Deref for ElifJson<T> {
33 type Target = T;
34
35 fn deref(&self) -> &Self::Target {
36 &self.0
37 }
38}
39
40impl<T> DerefMut for ElifJson<T> {
41 fn deref_mut(&mut self) -> &mut Self::Target {
42 &mut self.0
43 }
44}
45
46impl<T> From<T> for ElifJson<T> {
47 fn from(data: T) -> Self {
48 Self(data)
49 }
50}
51
52#[axum::async_trait]
54impl<T, S> FromRequest<S> for ElifJson<T>
55where
56 T: DeserializeOwned,
57 S: Send + Sync,
58{
59 type Rejection = JsonError;
60
61 async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
62 match Json::<T>::from_request(req, state).await {
63 Ok(Json(data)) => Ok(ElifJson(data)),
64 Err(rejection) => Err(JsonError::from_axum_json_rejection(rejection)),
65 }
66 }
67}
68
69impl<T> IntoElifResponse for ElifJson<T>
71where
72 T: Serialize,
73{
74 fn into_elif_response(self) -> ElifResponse {
75 match ElifResponse::ok().json(&self.0) {
76 Ok(response) => response,
77 Err(_) => ElifResponse::internal_server_error().text("JSON serialization failed"),
78 }
79 }
80}
81
82impl<T> IntoResponse for ElifJson<T>
84where
85 T: Serialize,
86{
87 fn into_response(self) -> Response {
88 match serde_json::to_vec(&self.0) {
89 Ok(bytes) => {
90 let mut response = Response::new(bytes.into());
91 response.headers_mut().insert(
92 axum::http::header::CONTENT_TYPE,
93 axum::http::HeaderValue::from_static("application/json"),
94 );
95 response
96 }
97 Err(err) => {
98 tracing::error!("JSON serialization failed: {}", err);
99 (
100 StatusCode::INTERNAL_SERVER_ERROR,
101 "Internal server error: JSON serialization failed"
102 ).into_response()
103 }
104 }
105 }
106}
107
108#[derive(Debug)]
110pub struct JsonError {
111 pub status: StatusCode,
112 pub message: String,
113 pub details: Option<String>,
114}
115
116impl JsonError {
117 pub fn new(status: StatusCode, message: String) -> Self {
119 Self {
120 status,
121 message,
122 details: None,
123 }
124 }
125
126 pub fn with_details(status: StatusCode, message: String, details: String) -> Self {
128 Self {
129 status,
130 message,
131 details: Some(details),
132 }
133 }
134
135 pub fn from_axum_json_rejection(rejection: axum::extract::rejection::JsonRejection) -> Self {
137 use axum::extract::rejection::JsonRejection::*;
138
139 match rejection {
140 JsonDataError(err) => {
141 Self::with_details(
142 StatusCode::BAD_REQUEST,
143 "Invalid JSON data".to_string(),
144 err.to_string(),
145 )
146 }
147 JsonSyntaxError(err) => {
148 Self::with_details(
149 StatusCode::BAD_REQUEST,
150 "JSON syntax error".to_string(),
151 err.to_string(),
152 )
153 }
154 MissingJsonContentType(_) => {
155 Self::new(
156 StatusCode::BAD_REQUEST,
157 "Missing 'Content-Type: application/json' header".to_string(),
158 )
159 }
160 BytesRejection(err) => {
161 Self::with_details(
162 StatusCode::BAD_REQUEST,
163 "Failed to read request body".to_string(),
164 err.to_string(),
165 )
166 }
167 _ => {
168 Self::new(
169 StatusCode::BAD_REQUEST,
170 "Invalid JSON request".to_string(),
171 )
172 }
173 }
174 }
175}
176
177impl IntoResponse for JsonError {
178 fn into_response(self) -> Response {
179 let error_body = if let Some(details) = self.details {
180 serde_json::json!({
181 "error": {
182 "code": self.status.as_u16(),
183 "message": self.message,
184 "details": details
185 }
186 })
187 } else {
188 serde_json::json!({
189 "error": {
190 "code": self.status.as_u16(),
191 "message": self.message
192 }
193 })
194 };
195
196 match ElifResponse::with_status(self.status)
197 .json_value(error_body)
198 .build()
199 {
200 Ok(response) => response,
201 Err(_) => {
202 (self.status, self.message).into_response()
204 }
205 }
206 }
207}
208
209pub struct JsonResponse;
211
212impl JsonResponse {
213 pub fn ok<T: Serialize>(data: &T) -> HttpResult<Response> {
215 ElifResponse::json_ok(data)
216 }
217
218 pub fn with_status<T: Serialize>(status: StatusCode, data: &T) -> HttpResult<Response> {
220 ElifResponse::with_status(status).json(data)?.build()
221 }
222
223 pub fn paginated<T: Serialize>(
225 data: &[T],
226 page: u32,
227 per_page: u32,
228 total: u64,
229 ) -> HttpResult<Response> {
230 let total_pages = (total as f64 / per_page as f64).ceil() as u32;
231
232 let response_data = serde_json::json!({
233 "data": data,
234 "pagination": {
235 "page": page,
236 "per_page": per_page,
237 "total": total,
238 "total_pages": total_pages,
239 "has_next": page < total_pages,
240 "has_prev": page > 1
241 }
242 });
243
244 ElifResponse::ok().json_value(response_data).build()
245 }
246
247 pub fn error(status: StatusCode, message: &str) -> HttpResult<Response> {
249 ElifResponse::json_error(status, message)
250 }
251
252 pub fn validation_error<T: Serialize>(errors: &T) -> HttpResult<Response> {
254 ElifResponse::validation_error(errors)
255 }
256
257 pub fn success_message(message: &str) -> HttpResult<Response> {
259 let response_data = serde_json::json!({
260 "success": true,
261 "message": message
262 });
263
264 ElifResponse::ok().json_value(response_data).build()
265 }
266
267 pub fn created<T: Serialize>(data: &T) -> HttpResult<Response> {
269 ElifResponse::created().json(data)?.build()
270 }
271
272 pub fn no_content() -> HttpResult<Response> {
274 ElifResponse::no_content().build()
275 }
276}
277
278#[derive(Debug, Serialize, Deserialize)]
280pub struct ValidationErrors {
281 pub errors: std::collections::HashMap<String, Vec<String>>,
282}
283
284impl ValidationErrors {
285 pub fn new() -> Self {
287 Self {
288 errors: std::collections::HashMap::new(),
289 }
290 }
291
292 pub fn add_error(&mut self, field: String, error: String) {
294 self.errors.entry(field).or_insert_with(Vec::new).push(error);
295 }
296
297 pub fn add_errors(&mut self, field: String, errors: Vec<String>) {
299 self.errors.entry(field).or_insert_with(Vec::new).extend(errors);
300 }
301
302 pub fn has_errors(&self) -> bool {
304 !self.errors.is_empty()
305 }
306
307 pub fn error_count(&self) -> usize {
309 self.errors.values().map(|v| v.len()).sum()
310 }
311
312 pub fn to_response(self) -> HttpResult<Response> {
314 JsonResponse::validation_error(&self)
315 }
316}
317
318impl Default for ValidationErrors {
319 fn default() -> Self {
320 Self::new()
321 }
322}
323
324#[derive(Debug, Serialize)]
326pub struct ApiResponse<T> {
327 pub success: bool,
328 pub data: Option<T>,
329 pub message: Option<String>,
330 pub errors: Option<serde_json::Value>,
331}
332
333impl<T: Serialize> ApiResponse<T> {
334 pub fn success(data: T) -> Self {
336 Self {
337 success: true,
338 data: Some(data),
339 message: None,
340 errors: None,
341 }
342 }
343
344 pub fn success_with_message(data: T, message: String) -> Self {
346 Self {
347 success: true,
348 data: Some(data),
349 message: Some(message),
350 errors: None,
351 }
352 }
353
354 pub fn error(message: String) -> ApiResponse<()> {
356 ApiResponse {
357 success: false,
358 data: None,
359 message: Some(message),
360 errors: None,
361 }
362 }
363
364 pub fn validation_error(message: String, errors: serde_json::Value) -> ApiResponse<()> {
366 ApiResponse {
367 success: false,
368 data: None,
369 message: Some(message),
370 errors: Some(errors),
371 }
372 }
373
374 pub fn to_response(self) -> HttpResult<Response> {
376 let status = if self.success {
377 StatusCode::OK
378 } else {
379 StatusCode::BAD_REQUEST
380 };
381
382 ElifResponse::with_status(status).json(&self)?.build()
383 }
384}
385
386impl<T: Serialize> IntoResponse for ApiResponse<T> {
387 fn into_response(self) -> Response {
388 match self.to_response() {
389 Ok(response) => response,
390 Err(e) => {
391 tracing::error!("Failed to create API response: {}", e);
392 (StatusCode::INTERNAL_SERVER_ERROR, "Internal server error").into_response()
393 }
394 }
395 }
396}
397
398#[cfg(test)]
399mod tests {
400 use super::*;
401 use serde_json::json;
402
403 #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
404 struct TestData {
405 name: String,
406 age: u32,
407 }
408
409 #[test]
410 fn test_elif_json_wrapper() {
411 let data = TestData {
412 name: "John".to_string(),
413 age: 30,
414 };
415
416 let json_data = ElifJson::new(data.clone());
417 assert_eq!(json_data.name, data.name);
418 assert_eq!(json_data.age, data.age);
419
420 let extracted = json_data.into_inner();
421 assert_eq!(extracted, data);
422 }
423
424 #[test]
425 fn test_validation_errors() {
426 let mut errors = ValidationErrors::new();
427 errors.add_error("name".to_string(), "Name is required".to_string());
428 errors.add_error("age".to_string(), "Age must be positive".to_string());
429
430 assert!(errors.has_errors());
431 assert_eq!(errors.error_count(), 2);
432 }
433
434 #[test]
435 fn test_api_response() {
436 let data = TestData {
437 name: "Jane".to_string(),
438 age: 25,
439 };
440
441 let success_response = ApiResponse::success(data);
442 assert!(success_response.success);
443 assert!(success_response.data.is_some());
444
445 let error_response = ApiResponse::<()>::error("Something went wrong".to_string());
446 assert!(!error_response.success);
447 assert!(error_response.data.is_none());
448 assert_eq!(error_response.message, Some("Something went wrong".to_string()));
449 }
450
451 #[test]
452 fn test_json_response_helpers() {
453 let data = vec![
454 TestData { name: "User1".to_string(), age: 20 },
455 TestData { name: "User2".to_string(), age: 25 },
456 ];
457
458 let response = JsonResponse::paginated(&data, 1, 10, 25);
460 assert!(response.is_ok());
461 }
462}