diff --git a/src/controllers/version/dependencies.rs b/src/controllers/version/dependencies.rs index 82299f1575c..26ef36b9062 100644 --- a/src/controllers/version/dependencies.rs +++ b/src/controllers/version/dependencies.rs @@ -3,12 +3,16 @@ use crate::app::AppState; use crate::models::Dependency; use crate::util::errors::AppResult; use crate::views::EncodableDependency; -use axum_extra::json; -use axum_extra::response::ErasedJson; +use axum::Json; use crates_io_database::schema::{crates, dependencies}; use diesel::prelude::*; use diesel_async::RunQueryDsl; +#[derive(Debug, Serialize, utoipa::ToSchema)] +pub struct Response { + pub dependencies: Vec, +} + /// Get crate version dependencies. /// /// This information can also be obtained directly from the index. @@ -21,16 +25,16 @@ use diesel_async::RunQueryDsl; path = "/api/v1/crates/{name}/{version}/dependencies", params(CrateVersionPath), tag = "versions", - responses((status = 200, description = "Successful Response")), + responses((status = 200, description = "Successful Response", body = inline(Response))), )] pub async fn get_version_dependencies( state: AppState, path: CrateVersionPath, -) -> AppResult { +) -> AppResult> { let mut conn = state.db_read().await?; let version = path.load_version(&mut conn).await?; - let deps = Dependency::belonging_to(&version) + let dependencies = Dependency::belonging_to(&version) .inner_join(crates::table) .select((Dependency::as_select(), crates::name)) .order((dependencies::optional, crates::name)) @@ -40,5 +44,5 @@ pub async fn get_version_dependencies( .map(|(dep, crate_name)| EncodableDependency::from_dep(dep, &crate_name)) .collect::>(); - Ok(json!({ "dependencies": deps })) + Ok(Json(Response { dependencies })) } diff --git a/src/snapshots/crates_io__openapi__tests__openapi_snapshot.snap b/src/snapshots/crates_io__openapi__tests__openapi_snapshot.snap index 6203e6587bf..52991927aa4 100644 --- a/src/snapshots/crates_io__openapi__tests__openapi_snapshot.snap +++ b/src/snapshots/crates_io__openapi__tests__openapi_snapshot.snap @@ -196,6 +196,78 @@ expression: response.json() ], "type": "object" }, + "EncodableDependency": { + "properties": { + "crate_id": { + "description": "The name of the crate this dependency points to.", + "example": "serde", + "type": "string" + }, + "default_features": { + "description": "Whether default features are enabled for this dependency.", + "example": true, + "type": "boolean" + }, + "downloads": { + "description": "The total number of downloads for the crate this dependency points to.", + "example": 123456, + "format": "int64", + "type": "integer" + }, + "features": { + "description": "The features explicitly enabled for this dependency.", + "items": { + "type": "string" + }, + "type": "array" + }, + "id": { + "description": "An opaque identifier for the dependency.", + "example": 169, + "format": "int32", + "type": "integer" + }, + "kind": { + "description": "The type of dependency this is (normal, dev, or build).", + "example": "normal", + "type": "string" + }, + "optional": { + "description": "Whether this dependency is optional.", + "type": "boolean" + }, + "req": { + "description": "The version requirement for this dependency.", + "example": "^1", + "type": "string" + }, + "target": { + "description": "The target platform for this dependency, if any.", + "type": [ + "string", + "null" + ] + }, + "version_id": { + "description": "The ID of the version this dependency belongs to.", + "example": 42, + "format": "int32", + "type": "integer" + } + }, + "required": [ + "id", + "version_id", + "crate_id", + "req", + "optional", + "default_features", + "features", + "kind", + "downloads" + ], + "type": "object" + }, "Keyword": { "properties": { "crates_cnt": { @@ -1838,6 +1910,24 @@ expression: response.json() ], "responses": { "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "dependencies": { + "items": { + "$ref": "#/components/schemas/EncodableDependency" + }, + "type": "array" + } + }, + "required": [ + "dependencies" + ], + "type": "object" + } + } + }, "description": "Successful Response" } }, diff --git a/src/views.rs b/src/views.rs index 1e8af8adce1..0a099853bb8 100644 --- a/src/views.rs +++ b/src/views.rs @@ -134,17 +134,43 @@ pub struct InvitationResponse { pub accepted: bool, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, utoipa::ToSchema)] pub struct EncodableDependency { + /// An opaque identifier for the dependency. + #[schema(example = 169)] pub id: i32, + + /// The ID of the version this dependency belongs to. + #[schema(example = 42)] pub version_id: i32, + + /// The name of the crate this dependency points to. + #[schema(example = "serde")] pub crate_id: String, + + /// The version requirement for this dependency. + #[schema(example = "^1")] pub req: String, + + /// Whether this dependency is optional. pub optional: bool, + + /// Whether default features are enabled for this dependency. + #[schema(example = true)] pub default_features: bool, + + /// The features explicitly enabled for this dependency. pub features: Vec, + + /// The target platform for this dependency, if any. pub target: Option, + + /// The type of dependency this is (normal, dev, or build). + #[schema(value_type = String, example = "normal")] pub kind: DependencyKind, + + /// The total number of downloads for the crate this dependency points to. + #[schema(example = 123_456)] pub downloads: i64, }