Skip to content

Commit

Permalink
Many fixes to the OpenAPI documentation (#1194)
Browse files Browse the repository at this point in the history
## Problem

According to
[openapi-generator-cli](https://www.npmjs.com/package/@openapitools/openapi-generator-cli),
our OpenAPI documentation contains several validation problems.

## Solution

This PR does not aim to fix every problem, but it does try to make the
documents usable.
  • Loading branch information
imobachgs authored May 14, 2024
2 parents c1b6814 + 1ef6d64 commit e2b27bd
Show file tree
Hide file tree
Showing 7 changed files with 303 additions and 147 deletions.
2 changes: 1 addition & 1 deletion rust/agama-lib/src/network/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ pub struct NetworkDevice {
pub state: DeviceState,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[derive(Clone, Debug, Default, Serialize, Deserialize, utoipa::ToSchema)]
pub struct NetworkConnection {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down
46 changes: 34 additions & 12 deletions rust/agama-server/src/l10n/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,18 +76,28 @@ pub struct LocaleConfig {
ui_keymap: Option<String>,
}

#[utoipa::path(get, path = "/l10n/timezones", responses(
(status = 200, description = "List of known timezones")
))]
#[utoipa::path(
get,
path = "/timezones",
context_path = "/api/l10n",
responses(
(status = 200, description = "List of known timezones", body = Vec<TimezoneEntry>)
)
)]
async fn timezones(State(state): State<LocaleState<'_>>) -> Json<Vec<TimezoneEntry>> {
let data = state.locale.read().await;
let timezones = data.timezones_db.entries().to_vec();
Json(timezones)
}

#[utoipa::path(get, path = "/l10n/keymaps", responses(
(status = 200, description = "List of known keymaps", body = Vec<Keymap>)
))]
#[utoipa::path(
get,
path = "/keymaps",
context_path = "/api/l10n",
responses(
(status = 200, description = "List of known keymaps", body = Vec<Keymap>)
)
)]
async fn keymaps(State(state): State<LocaleState<'_>>) -> Json<Vec<Keymap>> {
let data = state.locale.read().await;
let keymaps = data.keymaps_db.entries().to_vec();
Expand All @@ -96,9 +106,15 @@ async fn keymaps(State(state): State<LocaleState<'_>>) -> Json<Vec<Keymap>> {

// TODO: update all or nothing
// TODO: send only the attributes that have changed
#[utoipa::path(patch, path = "/l10n/config", responses(
(status = 204, description = "Set the locale configuration", body = LocaleConfig)
))]
#[utoipa::path(
patch,
path = "/config",
context_path = "/api/l10n",
operation_id = "set_l10n_config",
responses(
(status = 204, description = "Set the locale configuration", body = LocaleConfig)
)
)]
async fn set_config(
State(state): State<LocaleState<'_>>,
Json(value): Json<LocaleConfig>,
Expand Down Expand Up @@ -148,9 +164,15 @@ async fn set_config(
Ok(StatusCode::NO_CONTENT)
}

#[utoipa::path(get, path = "/l10n/config", responses(
(status = 200, description = "Localization configuration", body = LocaleConfig)
))]
#[utoipa::path(
get,
path = "/config",
context_path = "/api/l10n",
operation_id = "get_l10n_config",
responses(
(status = 200, description = "Localization configuration", body = LocaleConfig)
)
)]
async fn get_config(State(state): State<LocaleState<'_>>) -> Json<LocaleConfig> {
let data = state.locale.read().await;
Json(LocaleConfig {
Expand Down
44 changes: 32 additions & 12 deletions rust/agama-server/src/manager/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,36 +96,56 @@ pub async fn manager_service(dbus: zbus::Connection) -> Result<Router, ServiceEr
}

/// Starts the probing process.
#[utoipa::path(get, path = "/api/manager/probe", responses(
(status = 200, description = "The probing process was started.")
))]
#[utoipa::path(
get,
path = "/probe",
context_path = "/api/manager",
responses(
(status = 200, description = "The probing process was started.")
)
)]
async fn probe_action(State(state): State<ManagerState<'_>>) -> Result<(), Error> {
state.manager.probe().await?;
Ok(())
}

/// Starts the probing process.
#[utoipa::path(get, path = "/api/manager/install", responses(
(status = 200, description = "The installation process was started.")
))]
#[utoipa::path(
get,
path = "/install",
context_path = "/api/manager",
responses(
(status = 200, description = "The installation process was started.")
)
)]
async fn install_action(State(state): State<ManagerState<'_>>) -> Result<(), Error> {
state.manager.install().await?;
Ok(())
}

/// Executes the post installation tasks (e.g., rebooting the system).
#[utoipa::path(get, path = "/api/manager/install", responses(
(status = 200, description = "The installation tasks are executed.")
))]
#[utoipa::path(
get,
path = "/install",
context_path = "/api/manager",
responses(
(status = 200, description = "The installation tasks are executed.")
)
)]
async fn finish_action(State(state): State<ManagerState<'_>>) -> Result<(), Error> {
state.manager.finish().await?;
Ok(())
}

/// Returns the manager status.
#[utoipa::path(get, path = "/api/manager/installer", responses(
(status = 200, description = "Installation status.", body = ManagerStatus)
))]
#[utoipa::path(
get,
path = "/installer",
context_path = "/api/manager",
responses(
(status = 200, description = "Installation status.", body = InstallerStatus)
)
)]
async fn installer_status(
State(state): State<ManagerState<'_>>,
) -> Result<Json<InstallerStatus>, Error> {
Expand Down
2 changes: 1 addition & 1 deletion rust/agama-server/src/network/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl Default for StateConfig {
}
}

#[derive(Default, Clone, Debug, utoipa::ToSchema)]
#[derive(Default, Clone, Debug)]
pub struct NetworkState {
pub general_state: GeneralState,
pub access_points: Vec<AccessPoint>,
Expand Down
161 changes: 110 additions & 51 deletions rust/agama-server/src/network/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,29 @@ pub async fn network_service<T: Adapter + Send + Sync + 'static>(
.with_state(state))
}

#[utoipa::path(get, path = "/network/state", responses(
(status = 200, description = "Get general network config", body = GenereralState)
))]
#[utoipa::path(
get,
path = "/state",
context_path = "/api/network",
responses(
(status = 200, description = "Get general network config", body = GenereralState)
)
)]
async fn general_state(
State(state): State<NetworkServiceState>,
) -> Result<Json<GeneralState>, NetworkError> {
let general_state = state.network.get_state().await?;
Ok(Json(general_state))
}

#[utoipa::path(put, path = "/network/state", responses(
(status = 200, description = "Update general network config", body = GenereralState)
))]
#[utoipa::path(
put,
path = "/state",
context_path = "/api/network",
responses(
(status = 200, description = "Update general network config", body = GenereralState)
)
)]
async fn update_general_state(
State(state): State<NetworkServiceState>,
Json(value): Json<GeneralState>,
Expand All @@ -131,9 +141,14 @@ async fn update_general_state(
Ok(Json(state))
}

#[utoipa::path(get, path = "/network/wifi", responses(
(status = 200, description = "List of wireless networks", body = Vec<AccessPoint>)
))]
#[utoipa::path(
get,
path = "/wifi",
context_path = "/api/network",
responses(
(status = 200, description = "List of wireless networks", body = Vec<AccessPoint>)
)
)]
async fn wifi_networks(
State(state): State<NetworkServiceState>,
) -> Result<Json<Vec<AccessPoint>>, NetworkError> {
Expand All @@ -150,36 +165,28 @@ async fn wifi_networks(
Ok(Json(networks))
}

#[utoipa::path(get, path = "/network/devices", responses(
(status = 200, description = "List of devices", body = Vec<Device>)
))]
#[utoipa::path(
get,
path = "/devices",
context_path = "/api/network",
responses(
(status = 200, description = "List of devices", body = Vec<Device>)
)
)]
async fn devices(
State(state): State<NetworkServiceState>,
) -> Result<Json<Vec<Device>>, NetworkError> {
Ok(Json(state.network.get_devices().await?))
}

#[utoipa::path(get, path = "/network/connections/:id", responses(
(status = 200, description = "Get connection given by its ID", body = NetworkConnection)
))]
async fn connection(
State(state): State<NetworkServiceState>,
Path(id): Path<String>,
) -> Result<Json<NetworkConnection>, NetworkError> {
let conn = state
.network
.get_connection(&id)
.await?
.ok_or_else(|| NetworkError::UnknownConnection(id.clone()))?;

let conn = NetworkConnection::try_from(conn)?;

Ok(Json(conn))
}

#[utoipa::path(get, path = "/network/connections", responses(
(status = 200, description = "List of known connections", body = Vec<NetworkConnection>)
))]
#[utoipa::path(
get,
path = "/connections",
context_path = "/api/network",
responses(
(status = 200, description = "List of known connections", body = Vec<NetworkConnection>)
)
)]
async fn connections(
State(state): State<NetworkServiceState>,
) -> Result<Json<Vec<NetworkConnection>>, NetworkError> {
Expand All @@ -192,9 +199,14 @@ async fn connections(
Ok(Json(connections))
}

#[utoipa::path(post, path = "/network/connections", responses(
(status = 200, description = "Add a new connection", body = Connection)
))]
#[utoipa::path(
post,
path = "/connections",
context_path = "/api/network",
responses(
(status = 200, description = "Add a new connection", body = Connection)
)
)]
async fn add_connection(
State(state): State<NetworkServiceState>,
Json(conn): Json<NetworkConnection>,
Expand All @@ -209,9 +221,36 @@ async fn add_connection(
}
}

#[utoipa::path(delete, path = "/network/connections/:id", responses(
(status = 200, description = "Delete connection", body = Connection)
))]
#[utoipa::path(
get,
path = "/network/connections/:id",
responses(
(status = 200, description = "Get connection given by its ID", body = NetworkConnection)
)
)]
async fn connection(
State(state): State<NetworkServiceState>,
Path(id): Path<String>,
) -> Result<Json<NetworkConnection>, NetworkError> {
let conn = state
.network
.get_connection(&id)
.await?
.ok_or_else(|| NetworkError::UnknownConnection(id.clone()))?;

let conn = NetworkConnection::try_from(conn)?;

Ok(Json(conn))
}

#[utoipa::path(
delete,
path = "/connections/:id",
context_path = "/api/network",
responses(
(status = 200, description = "Delete connection", body = Connection)
)
)]
async fn delete_connection(
State(state): State<NetworkServiceState>,
Path(id): Path<String>,
Expand All @@ -223,9 +262,14 @@ async fn delete_connection(
}
}

#[utoipa::path(put, path = "/network/connections/:id", responses(
(status = 204, description = "Update connection", body = Connection)
))]
#[utoipa::path(
put,
path = "/connections/:id",
context_path = "/api/network",
responses(
(status = 204, description = "Update connection", body = Connection)
)
)]
async fn update_connection(
State(state): State<NetworkServiceState>,
Path(id): Path<String>,
Expand All @@ -248,9 +292,14 @@ async fn update_connection(
Ok(StatusCode::NO_CONTENT)
}

#[utoipa::path(get, path = "/network/connections/:id/connect", responses(
(status = 204, description = "Connect to the given connection", body = String)
))]
#[utoipa::path(
get,
path = "/connections/:id/connect",
context_path = "/api/network",
responses(
(status = 204, description = "Connect to the given connection", body = String)
)
)]
async fn connect(
State(state): State<NetworkServiceState>,
Path(id): Path<String>,
Expand All @@ -269,9 +318,14 @@ async fn connect(
Ok(StatusCode::NO_CONTENT)
}

#[utoipa::path(get, path = "/network/connections/:id/disconnect", responses(
(status = 204, description = "Connect to the given connection", body = String)
))]
#[utoipa::path(
get,
path = "/connections/:id/disconnect",
context_path = "/api/network",
responses(
(status = 204, description = "Connect to the given connection", body = String)
)
)]
async fn disconnect(
State(state): State<NetworkServiceState>,
Path(id): Path<String>,
Expand All @@ -290,9 +344,14 @@ async fn disconnect(
Ok(StatusCode::NO_CONTENT)
}

#[utoipa::path(put, path = "/network/system/apply", responses(
(status = 204, description = "Apply configuration")
))]
#[utoipa::path(
put,
path = "/system/apply",
context_path = "/api/network",
responses(
(status = 204, description = "Apply configuration")
)
)]
async fn apply(
State(state): State<NetworkServiceState>,
) -> Result<impl IntoResponse, NetworkError> {
Expand Down
Loading

0 comments on commit e2b27bd

Please sign in to comment.