feat: add pagination helper and integrate serde_urlencoded for query extraction
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -5446,6 +5446,7 @@ dependencies = [
|
||||
"sea-orm",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"tower",
|
||||
|
||||
@@ -30,9 +30,10 @@ jsonwebtoken = { version = "10.2.0", features = ["rust_crypto"] }
|
||||
uuid = { version = "1.19.0", features = ["v4", "serde", "fast-rng"] }
|
||||
tower-http = { version = "0.6.8", features = ["cors"] }
|
||||
reqwest = { version = "^0.12", features = ["json", "multipart", "stream"] }
|
||||
serde_urlencoded = { version = "0.7.1" }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3"
|
||||
|
||||
[lints.clippy]
|
||||
unwrap_used = "deny"
|
||||
unwrap_used = "deny"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
mod auth;
|
||||
mod health;
|
||||
mod helper;
|
||||
mod openapi;
|
||||
mod restricted;
|
||||
|
||||
|
||||
1
apps/api/src/routes/api/helper.rs
Normal file
1
apps/api/src/routes/api/helper.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod pagination;
|
||||
65
apps/api/src/routes/api/helper/pagination.rs
Normal file
65
apps/api/src/routes/api/helper/pagination.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
use axum::{
|
||||
extract::FromRequestParts,
|
||||
http::{StatusCode, request::Parts},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, utoipa::ToSchema)]
|
||||
/// Pagination parameters for API requests
|
||||
pub struct Pagination {
|
||||
/// Page number (1-based)
|
||||
pub page: u32,
|
||||
/// Items per page
|
||||
pub per_page: u32,
|
||||
}
|
||||
|
||||
impl Default for Pagination {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
page: 1,
|
||||
per_page: 20,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, utoipa::ToSchema)]
|
||||
/// Pagination information included in API responses
|
||||
pub struct PaginationInfo {
|
||||
/// Total number of items
|
||||
pub total_items: u64,
|
||||
/// Total number of pages
|
||||
pub total_pages: u32,
|
||||
/// Current page number
|
||||
pub current_page: u32,
|
||||
/// Items per page
|
||||
pub per_page: u32,
|
||||
}
|
||||
|
||||
/// Extractor for pagination parameters from query string
|
||||
pub struct ExtractPagination(pub Pagination);
|
||||
|
||||
impl<S> FromRequestParts<S> for ExtractPagination
|
||||
where
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = (StatusCode, &'static str);
|
||||
|
||||
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
|
||||
let query = parts.uri.query().unwrap_or("");
|
||||
let pagination: Pagination = serde_urlencoded::from_str(query).unwrap_or_default();
|
||||
|
||||
// validation
|
||||
if pagination.page == 0 {
|
||||
return Err((StatusCode::BAD_REQUEST, "page must be greater than 0"));
|
||||
}
|
||||
|
||||
if pagination.per_page < 1 || pagination.per_page > 100 {
|
||||
return Err((
|
||||
StatusCode::BAD_REQUEST,
|
||||
"per_page must be between 1 and 100",
|
||||
));
|
||||
}
|
||||
|
||||
Ok(ExtractPagination(pagination))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user