diff --git a/src/controllers/helpers/pagination.rs b/src/controllers/helpers/pagination.rs index 3100e121684..dfece901e17 100644 --- a/src/controllers/helpers/pagination.rs +++ b/src/controllers/helpers/pagination.rs @@ -55,6 +55,30 @@ impl PaginationOptions { } } +#[derive(Debug, Deserialize, utoipa::IntoParams)] +#[into_params(parameter_in = Query)] +pub struct PaginationQueryParams { + /// The page number to request. + /// + /// This parameter is mutually exclusive with `seek` and not supported for + /// all requests. + #[param(value_type = Option, minimum = 1)] + page: Option, + + /// The number of items to request per page. + #[param(value_type = Option, minimum = 1)] + per_page: Option, + + /// The seek key to request. + /// + /// This parameter is mutually exclusive with `page` and not supported for + /// all requests. + /// + /// The seek key can usually be found in the `meta.next_page` field of + /// paginated responses. + seek: Option, +} + pub(crate) struct PaginationOptionsBuilder { limit_page_numbers: bool, enable_pages: bool, @@ -80,14 +104,7 @@ impl PaginationOptionsBuilder { pub(crate) fn gather(self, parts: &Parts) -> AppResult { use axum::extract::Query; - #[derive(Debug, Deserialize)] - struct QueryParams { - page: Option, - per_page: Option, - seek: Option, - } - - let Query(params) = Query::::try_from_uri(&parts.uri) + let Query(params) = Query::::try_from_uri(&parts.uri) .map_err(|err| bad_request(err.body_text()))?; if params.seek.is_some() && params.page.is_some() { diff --git a/src/controllers/krate/search.rs b/src/controllers/krate/search.rs index 51627f3b143..889a44b1ab9 100644 --- a/src/controllers/krate/search.rs +++ b/src/controllers/krate/search.rs @@ -22,7 +22,7 @@ use crate::schema::*; use crate::util::errors::{bad_request, AppResult}; use crate::views::EncodableCrate; -use crate::controllers::helpers::pagination::{Page, PaginationOptions}; +use crate::controllers::helpers::pagination::{Page, PaginationOptions, PaginationQueryParams}; use crate::models::krate::ALL_COLUMNS; use crate::sql::{array_agg, canon_crate_name, lower}; use crate::util::string_excl_null::StringExclNull; @@ -37,7 +37,7 @@ use crate::util::RequestUtils; #[utoipa::path( get, path = "/api/v1/crates", - params(ListQueryParams), + params(ListQueryParams, PaginationQueryParams), tag = "crates", responses((status = 200, description = "Successful Response")), )] diff --git a/src/snapshots/crates_io__openapi__tests__openapi_snapshot.snap b/src/snapshots/crates_io__openapi__tests__openapi_snapshot.snap index c649c6bcff8..296e11f5bca 100644 --- a/src/snapshots/crates_io__openapi__tests__openapi_snapshot.snap +++ b/src/snapshots/crates_io__openapi__tests__openapi_snapshot.snap @@ -322,6 +322,46 @@ snapshot_kind: text }, "type": "array" } + }, + { + "description": "The page number to request.\n\nThis parameter is mutually exclusive with `seek` and not supported for\nall requests.", + "in": "query", + "name": "page", + "required": false, + "schema": { + "format": "int32", + "minimum": 1, + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "The number of items to request per page.", + "in": "query", + "name": "per_page", + "required": false, + "schema": { + "format": "int32", + "minimum": 1, + "type": [ + "integer", + "null" + ] + } + }, + { + "description": "The seek key to request.\n\nThis parameter is mutually exclusive with `page` and not supported for\nall requests.\n\nThe seek key can usually be found in the `meta.next_page` field of\npaginated responses.", + "in": "query", + "name": "seek", + "required": false, + "schema": { + "type": [ + "string", + "null" + ] + } } ], "responses": {