next_web_common/response/
api_response.rs

1use axum_core::response::{IntoResponse, Response};
2use serde::Serialize;
3
4/// A generic structure representing a standardized API response.
5///
6/// This struct is designed to encapsulate the result of an API call in a consistent format.
7/// It includes fields for the HTTP status code, a human-readable message, and optional data.
8/// The use of generics allows this structure to be flexible and work with any type that implements
9/// the `Serialize` trait, making it suitable for JSON serialization (e.g., using `serde`).
10///
11/// # Type Parameters
12/// - `T`: The type of the data field. It must implement the `Serialize` trait to ensure
13///   compatibility with serialization libraries like `serde`.
14///
15/// # Fields
16/// - `status: u16`  
17///   Represents the HTTP status code of the response (e.g., 200 for success, 404 for not found).
18///   This provides a machine-readable indicator of the response outcome.
19///
20/// - `message: String`  
21///   A human-readable description of the response. This can be used to provide additional context
22///   or details about the result (e.g., "Resource created successfully" or "Invalid input").
23///
24/// - `data: Option<T>`  
25///   Contains the payload of the response, if any. The use of `Option` allows this field to be
26///   omitted when there is no data to return (e.g., in case of an error). The type `T` is generic,
27///   enabling flexibility for different kinds of data (e.g., user information, list of items, etc.).
28///
29/// # Example
30/// ```rust
31/// use serde::Serialize;
32///
33/// #[derive(Serialize)]
34/// struct User {
35///     id: u32,
36///     name: String,
37/// }
38///
39/// let response = ApiResponse {
40///     status: 0,
41///     message: "User retrieved successfully".to_string(),
42///     data: Some(User {
43///         id: 1,
44///         name: "Alice".to_string(),
45///     }),
46/// };
47///
48/// // Serialize the response to JSON
49/// let json_response = serde_json::to_string(&response).unwrap();
50/// println!("{}", json_response);
51/// ```
52#[derive(Debug, Serialize)]
53pub struct ApiResponse<T: Serialize> {
54    status: u16,
55    message: String,
56    data: Option<T>,
57}
58
59impl<T: Serialize> ApiResponse<T> {
60    pub fn new(status: u16, message: String, data: T) -> Self {
61        ApiResponse {
62            status,
63            message,
64            data: Some(data),
65        }
66    }
67
68    pub fn get_status(&self) -> u16 {
69        self.status
70    }
71
72    pub fn get_message(&self) -> &str {
73        &self.message
74    }
75
76    pub fn get_data(&self) -> Option<&T> {
77        self.data.as_ref()
78    }
79
80    pub fn set_status(mut self, status_code: u16) -> ApiResponse<T> {
81        self.status = status_code;
82        return self;
83    }
84
85    pub fn set_message(mut self, message: impl Into<String>) -> ApiResponse<T> {
86        self.message = message.into();
87        return self;
88    }
89
90    pub fn set_data(mut self, data: T) -> ApiResponse<T> {
91        self.data = Some(data);
92        return self;
93    }
94}
95
96impl<T: Serialize> ApiResponse<T> {
97    pub fn ok(data: T) -> ApiResponse<T> {
98        return ApiResponse {
99            status: 0,
100            message: "ok".into(),
101            data: Some(data),
102        };
103    }
104
105    pub fn fail(data: T) -> ApiResponse<T> {
106        return ApiResponse {
107            status: 500,
108            message: "fail".into(),
109            data: Some(data),
110        };
111    }
112
113    pub fn empty() -> ApiResponse<T> {
114        return ApiResponse {
115            status: 204,
116            message: "".into(),
117            data: None,
118        };
119    }
120}
121
122impl<T> IntoResponse for ApiResponse<T>
123where
124    T: Serialize,
125{
126    fn into_response(self) -> Response {
127        Response::builder()
128            .header("Content-Type", "application/json")
129            .status(200)
130            .body(serde_json::json!(self).to_string().into())
131            .unwrap()
132    }
133}