refactor(api): share Pagination across admin/public; cover get-by-id auth
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,10 +10,10 @@ use axum::{
|
||||
routing::get,
|
||||
};
|
||||
use domain::{CatalogueObject, ObjectId};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::Serialize;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use crate::AppState;
|
||||
use crate::{AppState, pagination::Pagination};
|
||||
|
||||
/// A localized label `{ lang, label }` (shared across admin views).
|
||||
#[derive(Serialize, ToSchema)]
|
||||
@@ -69,25 +69,6 @@ pub(crate) struct AdminObjectPage {
|
||||
pub offset: i64,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub(crate) struct Pagination {
|
||||
limit: Option<i64>,
|
||||
offset: Option<i64>,
|
||||
}
|
||||
|
||||
const DEFAULT_LIMIT: i64 = 50;
|
||||
const MAX_LIMIT: i64 = 200;
|
||||
|
||||
impl Pagination {
|
||||
fn limit(&self) -> i64 {
|
||||
self.limit.unwrap_or(DEFAULT_LIMIT).clamp(1, MAX_LIMIT)
|
||||
}
|
||||
|
||||
fn offset(&self) -> i64 {
|
||||
self.offset.unwrap_or(0).max(0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Format a `time::Date` as `YYYY-MM-DD`.
|
||||
pub(crate) fn format_date(d: time::Date) -> String {
|
||||
let fmt = time::macros::format_description!("[year]-[month]-[day]");
|
||||
|
||||
@@ -4,6 +4,7 @@ mod admin;
|
||||
mod admin_objects;
|
||||
mod health;
|
||||
mod openapi;
|
||||
mod pagination;
|
||||
mod public;
|
||||
|
||||
use axum::Router;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
//! Shared pagination query parameters used by both admin and public handlers.
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
pub(crate) const DEFAULT_LIMIT: i64 = 50;
|
||||
pub(crate) const MAX_LIMIT: i64 = 200;
|
||||
|
||||
/// Pagination query parameters with sane defaults and a hard cap.
|
||||
#[derive(Deserialize)]
|
||||
pub(crate) struct Pagination {
|
||||
pub(crate) limit: Option<i64>,
|
||||
pub(crate) offset: Option<i64>,
|
||||
}
|
||||
|
||||
impl Pagination {
|
||||
pub(crate) fn limit(&self) -> i64 {
|
||||
self.limit.unwrap_or(DEFAULT_LIMIT).clamp(1, MAX_LIMIT)
|
||||
}
|
||||
|
||||
pub(crate) fn offset(&self) -> i64 {
|
||||
self.offset.unwrap_or(0).max(0)
|
||||
}
|
||||
}
|
||||
@@ -14,10 +14,10 @@ use axum::{
|
||||
routing::get,
|
||||
};
|
||||
use domain::{CatalogueObject, ObjectId};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::Serialize;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use crate::AppState;
|
||||
use crate::{AppState, pagination::Pagination};
|
||||
|
||||
/// A catalogue object as exposed on the public surface (public-safe fields only).
|
||||
#[derive(Serialize, ToSchema)]
|
||||
@@ -50,26 +50,6 @@ pub(crate) struct PublicObjectPage {
|
||||
pub offset: i64,
|
||||
}
|
||||
|
||||
/// Pagination query parameters with sane defaults and a hard cap.
|
||||
#[derive(Deserialize)]
|
||||
pub(crate) struct Pagination {
|
||||
limit: Option<i64>,
|
||||
offset: Option<i64>,
|
||||
}
|
||||
|
||||
const DEFAULT_LIMIT: i64 = 50;
|
||||
const MAX_LIMIT: i64 = 200;
|
||||
|
||||
impl Pagination {
|
||||
fn limit(&self) -> i64 {
|
||||
self.limit.unwrap_or(DEFAULT_LIMIT).clamp(1, MAX_LIMIT)
|
||||
}
|
||||
|
||||
fn offset(&self) -> i64 {
|
||||
self.offset.unwrap_or(0).max(0)
|
||||
}
|
||||
}
|
||||
|
||||
/// List public objects (paginated).
|
||||
#[utoipa::path(
|
||||
get,
|
||||
|
||||
Reference in New Issue
Block a user