diff --git a/Cargo.lock b/Cargo.lock index 4318b165..ea74623c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr" @@ -255,6 +255,30 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum-extra" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fc6f625a1f7705c6cf62d0d070794e94668988b1c38111baeec177c715f7b" +dependencies = [ + "axum", + "axum-core", + "bytes", + "form_urlencoded", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "serde", + "serde_html_form", + "serde_path_to_error", + "tower 0.5.2", + "tower-layer", + "tower-service", +] + [[package]] name = "axum-macros" version = "0.5.0" @@ -709,6 +733,7 @@ dependencies = [ "assert_cmd", "async-trait", "axum", + "axum-extra", "axum-macros", "axum-test", "chrono", @@ -1893,6 +1918,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_html_form" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d2de91cf02bbc07cde38891769ccd5d4f073d22a40683aa4bc7a95781aaa2c4" +dependencies = [ + "form_urlencoded", + "indexmap 2.5.0", + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_json" version = "1.0.139" diff --git a/Cargo.toml b/Cargo.toml index 7071eb39..e651396a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ anyhow = "1" async-trait = "0.1.86" axum = "0.8.1" # web framework axum-macros = "0.5.0" +axum-extra = { version = "0.10.0", features = ["query"] } clap = { version = "4.5.30", features = ["derive"] } # command-line parser config = "0.15.8" # Layered configuration with strong support for 12-factor applications chrono = { version = "0.4.39", features = ["serde"] } diff --git a/src/api/handler/v1/projects/handlers.rs b/src/api/handler/v1/projects/handlers.rs index c47a93f8..1fbb82d9 100644 --- a/src/api/handler/v1/projects/handlers.rs +++ b/src/api/handler/v1/projects/handlers.rs @@ -1,16 +1,17 @@ use std::sync::Arc; -use axum::extract::{Path, Query, State}; +use axum::extract::{Path, State}; use axum::http::StatusCode; use axum::response::{IntoResponse, Response}; use axum::Json; +use axum_extra::extract::OptionalQuery; use tracing::{instrument, trace}; use crate::api::handler::v1::projects::responses::{ ProjectMetadataDto, ProjectMetadataWithInfoDto, }; use crate::app_state::AppState; -use crate::domain::metadata_repository::{OptionalFilter, OptionalPagination}; +use crate::domain::metadata_repository::{Filter, Pagination}; use crate::domain::model::draft_model::Shortcode; use crate::error::DspMetaError; @@ -41,12 +42,12 @@ pub async fn get_by_shortcode( #[axum_macros::debug_handler] pub async fn get_by_page_and_filter( State(state): State>, - pagination: Query, - filter: Query, + pagination: OptionalQuery, + filter: OptionalQuery, ) -> Result { trace!("entered get_all_project_metadata()"); - let pagination = pagination.0.or_default(); - let filter = filter.0.or_default(); + let pagination = pagination.0.unwrap_or_default(); + let filter = filter.0.unwrap_or_default(); let page = state.metadata_service.find(&filter, &pagination)?; let mut response = Json( page.data diff --git a/src/domain/metadata_repository.rs b/src/domain/metadata_repository.rs index 3fa06b52..81e86386 100644 --- a/src/domain/metadata_repository.rs +++ b/src/domain/metadata_repository.rs @@ -27,18 +27,6 @@ impl Default for Pagination { } } -#[derive(Debug, Deserialize, Default, Clone)] -pub struct OptionalPagination { - #[serde(flatten)] - pub pagination: Option, -} - -impl OptionalPagination { - pub fn or_default(&self) -> Pagination { - self.pagination.clone().unwrap_or_default() - } -} - #[derive(Deserialize, Default, Debug, Clone)] pub struct Filter { #[serde(rename = "q")] @@ -47,18 +35,6 @@ pub struct Filter { pub filter: Option, } -#[derive(Debug, Deserialize, Default, Clone)] -pub struct OptionalFilter { - #[serde(flatten)] - pub filter: Option, -} - -impl OptionalFilter { - pub fn or_default(&self) -> Filter { - self.filter.clone().unwrap_or_default() - } -} - pub struct Page { pub data: Vec, pub total: usize,