Skip to content

Commit 513e6af

Browse files
committed
Improve OpenAPI documentation for GET /api/v1/crates/{name}/versions endpoints
1 parent a4af217 commit 513e6af

File tree

2 files changed

+82
-16
lines changed

2 files changed

+82
-16
lines changed

src/controllers/krate/versions.rs

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,5 @@
11
//! Endpoint for versions of a crate
22
3-
use axum::extract::FromRequestParts;
4-
use axum_extra::extract::Query;
5-
use axum_extra::json;
6-
use axum_extra::response::ErasedJson;
7-
use diesel::dsl::not;
8-
use diesel::prelude::*;
9-
use diesel_async::{AsyncPgConnection, RunQueryDsl};
10-
use futures_util::{TryStreamExt, future};
11-
use http::request::Parts;
12-
use indexmap::{IndexMap, IndexSet};
13-
use std::str::FromStr;
14-
153
use crate::app::AppState;
164
use crate::controllers::helpers::pagination::{
175
Page, PaginationOptions, PaginationQueryParams, encode_seek,
@@ -23,6 +11,16 @@ use crate::util::RequestUtils;
2311
use crate::util::errors::{AppResult, BoxedAppError, bad_request};
2412
use crate::util::string_excl_null::StringExclNull;
2513
use crate::views::EncodableVersion;
14+
use axum::Json;
15+
use axum::extract::FromRequestParts;
16+
use axum_extra::extract::Query;
17+
use diesel::dsl::not;
18+
use diesel::prelude::*;
19+
use diesel_async::{AsyncPgConnection, RunQueryDsl};
20+
use futures_util::{TryStreamExt, future};
21+
use http::request::Parts;
22+
use indexmap::{IndexMap, IndexSet};
23+
use std::str::FromStr;
2624

2725
#[derive(Debug, Deserialize, FromRequestParts, utoipa::IntoParams)]
2826
#[from_request(via(Query))]
@@ -62,21 +60,29 @@ impl ListQueryParams {
6260
}
6361
}
6462

63+
#[derive(Debug, Serialize, utoipa::ToSchema)]
64+
pub struct ListResponse {
65+
versions: Vec<EncodableVersion>,
66+
67+
#[schema(inline)]
68+
meta: ResponseMeta,
69+
}
70+
6571
/// List all versions of a crate.
6672
#[utoipa::path(
6773
get,
6874
path = "/api/v1/crates/{name}/versions",
6975
params(CratePath, ListQueryParams, PaginationQueryParams),
7076
tag = "versions",
71-
responses((status = 200, description = "Successful Response")),
77+
responses((status = 200, description = "Successful Response", body = inline(ListResponse))),
7278
)]
7379
pub async fn list_versions(
7480
state: AppState,
7581
path: CratePath,
7682
params: ListQueryParams,
7783
pagination: PaginationQueryParams,
7884
req: Parts,
79-
) -> AppResult<ErasedJson> {
85+
) -> AppResult<Json<ListResponse>> {
8086
let mut conn = state.db_read().await?;
8187

8288
let crate_id = path.load_crate_id(&mut conn).await?;
@@ -113,7 +119,10 @@ pub async fn list_versions(
113119
.map(|((v, pb), aas)| EncodableVersion::from(v, &path.name, pb, aas))
114120
.collect::<Vec<_>>();
115121

116-
Ok(json!({ "versions": versions, "meta": versions_and_publishers.meta }))
122+
Ok(Json(ListResponse {
123+
versions,
124+
meta: versions_and_publishers.meta,
125+
}))
117126
}
118127

119128
/// Seek-based pagination of versions by date
@@ -433,11 +442,20 @@ struct PaginatedVersionsAndPublishers {
433442
meta: ResponseMeta,
434443
}
435444

436-
#[derive(Serialize)]
445+
#[derive(Debug, Serialize, utoipa::ToSchema)]
437446
struct ResponseMeta {
447+
/// The total number of versions belonging to the crate.
448+
#[schema(example = 123)]
438449
total: i64,
450+
451+
/// Query string to the next page of results, if any.
452+
#[schema(example = "?page=3")]
439453
next_page: Option<String>,
454+
455+
/// Additional data about the crate's release tracks,
456+
/// if `?include=release_tracks` is used.
440457
#[serde(skip_serializing_if = "Option::is_none")]
458+
#[schema(value_type = Option<Object>)]
441459
release_tracks: Option<ReleaseTracks>,
442460
}
443461

src/snapshots/crates_io__openapi__tests__openapi_snapshot.snap

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2465,6 +2465,54 @@ expression: response.json()
24652465
],
24662466
"responses": {
24672467
"200": {
2468+
"content": {
2469+
"application/json": {
2470+
"schema": {
2471+
"properties": {
2472+
"meta": {
2473+
"properties": {
2474+
"next_page": {
2475+
"description": "Query string to the next page of results, if any.",
2476+
"example": "?page=3",
2477+
"type": [
2478+
"string",
2479+
"null"
2480+
]
2481+
},
2482+
"release_tracks": {
2483+
"description": "Additional data about the crate's release tracks,\nif `?include=release_tracks` is used.",
2484+
"type": [
2485+
"object",
2486+
"null"
2487+
]
2488+
},
2489+
"total": {
2490+
"description": "The total number of versions belonging to the crate.",
2491+
"example": 123,
2492+
"format": "int64",
2493+
"type": "integer"
2494+
}
2495+
},
2496+
"required": [
2497+
"total"
2498+
],
2499+
"type": "object"
2500+
},
2501+
"versions": {
2502+
"items": {
2503+
"$ref": "#/components/schemas/Version"
2504+
},
2505+
"type": "array"
2506+
}
2507+
},
2508+
"required": [
2509+
"versions",
2510+
"meta"
2511+
],
2512+
"type": "object"
2513+
}
2514+
}
2515+
},
24682516
"description": "Successful Response"
24692517
}
24702518
},

0 commit comments

Comments
 (0)