use axum::{
response::{IntoResponse, Response},
Json,
};
use serde::Serialize;
#[derive(Debug, Clone, Serialize)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub struct ListResponse<T: Serialize> {
pub data: Vec<T>,
pub total: i64,
pub limit: u32,
pub offset: u32,
}
impl<T: Serialize> IntoResponse for ListResponse<T> {
fn into_response(self) -> Response {
Json(self).into_response()
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[derive(Serialize)]
struct Item {
id: String,
}
#[test]
fn serializes_fields_correctly() {
let resp = ListResponse {
data: vec![Item { id: "abc".into() }],
total: 10,
limit: 25,
offset: 0,
};
let v = serde_json::to_value(&resp).unwrap();
assert_eq!(v["total"], 10);
assert_eq!(v["limit"], 25);
assert_eq!(v["offset"], 0);
assert_eq!(v["data"][0]["id"], "abc");
}
#[test]
fn empty_data_serializes() {
let resp: ListResponse<Item> = ListResponse {
data: vec![],
total: 0,
limit: 50,
offset: 0,
};
let v = serde_json::to_value(&resp).unwrap();
assert_eq!(v["data"], json!([]));
assert_eq!(v["total"], 0);
}
#[test]
fn offset_pagination_fields() {
let resp: ListResponse<Item> = ListResponse {
data: vec![],
total: 100,
limit: 10,
offset: 30,
};
let v = serde_json::to_value(&resp).unwrap();
assert_eq!(v["limit"], 10);
assert_eq!(v["offset"], 30);
}
}