Skip to content

Commit aa2f5cb

Browse files
committed
Improve OpenAPI documentation for GET /api/v1/crates endpoints
1 parent daa58ad commit aa2f5cb

File tree

2 files changed

+81
-10
lines changed

2 files changed

+81
-10
lines changed

src/controllers/krate/search.rs

+32-10
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
//! Endpoint for searching and discovery functionality
22
33
use crate::auth::AuthCheck;
4+
use axum::Json;
45
use axum::extract::FromRequestParts;
56
use axum_extra::extract::Query;
6-
use axum_extra::json;
7-
use axum_extra::response::ErasedJson;
87
use derive_more::Deref;
98
use diesel::dsl::{InnerJoinQuerySource, LeftJoinQuerySource, exists};
109
use diesel::prelude::*;
@@ -28,6 +27,29 @@ use crate::util::RequestUtils;
2827
use crate::util::string_excl_null::StringExclNull;
2928
use crates_io_diesel_helpers::{array_agg, canon_crate_name, lower};
3029

30+
#[derive(Debug, Serialize, utoipa::ToSchema)]
31+
pub struct ListResponse {
32+
crates: Vec<EncodableCrate>,
33+
34+
#[schema(inline)]
35+
meta: ListMeta,
36+
}
37+
38+
#[derive(Debug, Serialize, utoipa::ToSchema)]
39+
pub struct ListMeta {
40+
/// The total number of crates that match the query.
41+
#[schema(example = 123)]
42+
total: i64,
43+
44+
/// Query string to the next page of results, if any.
45+
#[schema(example = "?page=3")]
46+
next_page: Option<String>,
47+
48+
/// Query string to the previous page of results, if any.
49+
#[schema(example = "?page=1")]
50+
prev_page: Option<String>,
51+
}
52+
3153
/// Returns a list of crates.
3254
///
3355
/// Called in a variety of scenarios in the front end, including:
@@ -44,13 +66,13 @@ use crates_io_diesel_helpers::{array_agg, canon_crate_name, lower};
4466
("cookie" = []),
4567
),
4668
tag = "crates",
47-
responses((status = 200, description = "Successful Response")),
69+
responses((status = 200, description = "Successful Response", body = inline(ListResponse))),
4870
)]
4971
pub async fn list_crates(
5072
app: AppState,
5173
params: ListQueryParams,
5274
req: Parts,
53-
) -> AppResult<ErasedJson> {
75+
) -> AppResult<Json<ListResponse>> {
5476
// Notes:
5577
// The different use cases this function covers is handled through passing
5678
// in parameters in the GET request.
@@ -240,12 +262,12 @@ pub async fn list_crates(
240262
})
241263
.collect::<Vec<_>>();
242264

243-
Ok(json!({
244-
"crates": crates,
245-
"meta": {
246-
"total": total,
247-
"next_page": next_page,
248-
"prev_page": prev_page,
265+
Ok(Json(ListResponse {
266+
crates,
267+
meta: ListMeta {
268+
total,
269+
next_page,
270+
prev_page,
249271
},
250272
}))
251273
}

src/snapshots/crates_io__openapi__tests__openapi_snapshot.snap

+49
Original file line numberDiff line numberDiff line change
@@ -1557,6 +1557,55 @@ expression: response.json()
15571557
],
15581558
"responses": {
15591559
"200": {
1560+
"content": {
1561+
"application/json": {
1562+
"schema": {
1563+
"properties": {
1564+
"crates": {
1565+
"items": {
1566+
"$ref": "#/components/schemas/Crate"
1567+
},
1568+
"type": "array"
1569+
},
1570+
"meta": {
1571+
"properties": {
1572+
"next_page": {
1573+
"description": "Query string to the next page of results, if any.",
1574+
"example": "?page=3",
1575+
"type": [
1576+
"string",
1577+
"null"
1578+
]
1579+
},
1580+
"prev_page": {
1581+
"description": "Query string to the previous page of results, if any.",
1582+
"example": "?page=1",
1583+
"type": [
1584+
"string",
1585+
"null"
1586+
]
1587+
},
1588+
"total": {
1589+
"description": "The total number of crates that match the query.",
1590+
"example": 123,
1591+
"format": "int64",
1592+
"type": "integer"
1593+
}
1594+
},
1595+
"required": [
1596+
"total"
1597+
],
1598+
"type": "object"
1599+
}
1600+
},
1601+
"required": [
1602+
"crates",
1603+
"meta"
1604+
],
1605+
"type": "object"
1606+
}
1607+
}
1608+
},
15601609
"description": "Successful Response"
15611610
}
15621611
},

0 commit comments

Comments
 (0)