use axum::{Json, http::StatusCode, response::IntoResponse};
use serde::Serialize;
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub struct ApiResponse<T>
where
T: Serialize,
{
pub success: bool,
pub err_code: String,
pub err_message: String,
pub data: Option<T>,
}
impl<T> ApiResponse<T>
where
T: Serialize,
{
pub fn success(data: T) -> Self {
Self {
success: true,
err_code: "0".to_string(),
err_message: String::new(),
data: Some(data),
}
}
pub fn success_no_data() -> Self {
Self {
success: true,
err_code: "0".to_string(),
err_message: String::new(),
data: None,
}
}
pub fn fail(code: impl Into<String>, message: impl Into<String>) -> Self {
Self {
success: false,
err_code: code.into(),
err_message: message.into(),
data: None,
}
}
}
impl<T> IntoResponse for ApiResponse<T>
where
T: Serialize,
{
fn into_response(self) -> axum::response::Response {
(StatusCode::OK, Json(self)).into_response()
}
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub struct PageResponse<T>
where
T: Serialize,
{
pub success: bool,
pub err_code: String,
pub err_message: String,
pub data: Vec<T>,
pub total: i64,
pub page_size: i64,
pub has_more: bool,
pub current_page: i64,
pub total_pages: i64,
}
impl<T> PageResponse<T>
where
T: Serialize,
{
pub fn success(data: Vec<T>, total: i64, page_size: i64, current_page: i64) -> Self {
Self {
success: true,
err_code: "0".to_string(),
err_message: String::new(),
data,
total,
page_size,
has_more: total > page_size * current_page,
current_page,
total_pages: if page_size <= 0 {
0
} else {
(total + page_size - 1) / page_size
},
}
}
pub fn empty() -> Self {
Self {
success: true,
err_code: "0".to_string(),
err_message: String::new(),
data: Vec::new(),
total: 0,
page_size: 0,
has_more: false,
current_page: 0,
total_pages: 0,
}
}
}
impl<T> IntoResponse for PageResponse<T>
where
T: Serialize,
{
fn into_response(self) -> axum::response::Response {
(StatusCode::OK, Json(self)).into_response()
}
}
#[cfg(test)]
mod tests {
use super::{ApiResponse, PageResponse};
#[test]
fn response_success_uses_zero_error_code() {
let response = ApiResponse::success("ok");
assert!(response.success);
assert_eq!(response.err_code, "0");
assert_eq!(response.data, Some("ok"));
}
#[test]
fn page_response_calculates_total_pages() {
let response = PageResponse::success(vec![1, 2], 11, 5, 2);
assert!(response.has_more);
assert_eq!(response.total_pages, 3);
}
}