api/response/mod.rs
1//! Standard API response wrapper.
2//!
3//! `ApiResponse<T>` enforces a consistent JSON structure for all endpoints:
4//! ```json
5//! {
6//! "success": true|false,
7//! "data": { ... } | null,
8//! "message": "Description"
9//! }
10//! ```
11//! Use the provided constructors for success or error responses.
12
13use serde::Serialize;
14
15/// Standardized API response wrapper for all outgoing JSON responses.
16///
17/// This struct enforces a consistent response structure across all endpoints:
18/// ```json
19/// {
20/// "success": true,
21/// "data": { ... },
22/// "message": "Some message"
23/// }
24/// ```
25///
26/// - `T` is the type of the `data` payload.
27/// - `success` is a boolean indicating operation status.
28/// - `message` provides a human-readable context string.
29///
30/// ## Example (success):
31/// ```json
32/// {
33/// "success": true,
34/// "data": { "id": 1, "name": "Alice" },
35/// "message": "User fetched successfully"
36/// }
37/// ```
38///
39/// ## Example (error):
40/// ```json
41/// {
42/// "success": false,
43/// "data": {},
44/// "message": "User not found"
45/// }
46/// ```
47#[derive(Serialize)]
48pub struct ApiResponse<T>
49where
50 T: Serialize,
51{
52 pub success: bool,
53
54 #[serde(skip_serializing_if = "Option::is_none")]
55 pub data: Option<T>,
56
57 pub message: String,
58}
59
60impl<T> ApiResponse<T>
61where
62 T: Serialize,
63{
64 /// Constructs a success response with the given data and message.
65 ///
66 /// # Arguments
67 /// - `data`: The result payload.
68 /// - `message`: A descriptive message to accompany the success.
69 pub fn success(data: T, message: impl Into<String>) -> Self {
70 ApiResponse {
71 success: true,
72 data: Some(data),
73 message: message.into(),
74 }
75 }
76
77 /// Constructs a success response with no data, only a message.
78 ///
79 /// # Arguments
80 /// - `message`: A descriptive message to accompany the success.
81 pub fn success_without_data(message: impl Into<String>) -> Self {
82 ApiResponse {
83 success: true,
84 data: None,
85 message: message.into(),
86 }
87 }
88
89 /// Constructs an error response with a message and no `data`.
90 ///
91 /// # Arguments
92 /// - `message`: A description of the error.
93 pub fn error(message: impl Into<String>) -> Self {
94 ApiResponse {
95 success: false,
96 data: None,
97 message: message.into(),
98 }
99 }
100}