feat: add workspace foundation

This commit is contained in:
a.tolmachev
2026-03-29 21:45:53 +03:00
parent d3ab565fff
commit d757adb192
19 changed files with 743 additions and 109 deletions
+30 -5
View File
@@ -2,30 +2,55 @@ use axum::{
Json,
extract::{Path, State},
};
use serde::Deserialize;
use serde_json::{Value, json};
use crate::{error::ApiError, service::AuthProfilePayload, state::AppState};
pub async fn list_auth_profiles(State(state): State<AppState>) -> Result<Json<Value>, ApiError> {
let items = state.service.list_auth_profiles().await?;
#[derive(Deserialize)]
pub struct WorkspacePath {
pub workspace_id: String,
}
#[derive(Deserialize)]
pub struct WorkspaceAuthProfilePath {
pub workspace_id: String,
pub auth_profile_id: String,
}
pub async fn list_auth_profiles(
Path(path): Path<WorkspacePath>,
State(state): State<AppState>,
) -> Result<Json<Value>, ApiError> {
let items = state
.service
.list_auth_profiles(&path.workspace_id.as_str().into())
.await?;
Ok(Json(json!({ "items": items })))
}
pub async fn create_auth_profile(
Path(path): Path<WorkspacePath>,
State(state): State<AppState>,
Json(payload): Json<AuthProfilePayload>,
) -> Result<Json<Value>, ApiError> {
let profile = state.service.create_auth_profile(payload).await?;
let profile = state
.service
.create_auth_profile(&path.workspace_id.as_str().into(), payload)
.await?;
Ok(Json(json!(profile)))
}
pub async fn get_auth_profile(
Path(auth_profile_id): Path<String>,
Path(path): Path<WorkspaceAuthProfilePath>,
State(state): State<AppState>,
) -> Result<Json<Value>, ApiError> {
let profile = state
.service
.get_auth_profile(&auth_profile_id.as_str().into())
.get_auth_profile(
&path.workspace_id.as_str().into(),
&path.auth_profile_id.as_str().into(),
)
.await?;
Ok(Json(json!(profile)))
}
+96 -28
View File
@@ -5,6 +5,7 @@ use axum::{
http::{HeaderMap, StatusCode, header},
response::IntoResponse,
};
use serde::Deserialize;
use serde_json::{Value, json};
use crate::{
@@ -16,86 +17,134 @@ use crate::{
state::AppState,
};
pub async fn list_operations(State(state): State<AppState>) -> Result<Json<Value>, ApiError> {
let items = state.service.list_operations().await?;
#[derive(Deserialize)]
pub struct WorkspacePath {
pub workspace_id: String,
}
#[derive(Deserialize)]
pub struct WorkspaceOperationPath {
pub workspace_id: String,
pub operation_id: String,
}
#[derive(Deserialize)]
pub struct WorkspaceOperationVersionPath {
pub workspace_id: String,
pub operation_id: String,
pub version: u32,
}
pub async fn list_operations(
Path(path): Path<WorkspacePath>,
State(state): State<AppState>,
) -> Result<Json<Value>, ApiError> {
let items = state
.service
.list_operations(&path.workspace_id.as_str().into())
.await?;
Ok(Json(json!({ "items": items })))
}
pub async fn create_operation(
Path(path): Path<WorkspacePath>,
State(state): State<AppState>,
Json(payload): Json<OperationPayload>,
) -> Result<Json<Value>, ApiError> {
let created = state.service.create_operation(payload).await?;
let created = state
.service
.create_operation(&path.workspace_id.as_str().into(), payload)
.await?;
Ok(Json(json!(created)))
}
pub async fn get_operation(
Path(operation_id): Path<String>,
Path(path): Path<WorkspaceOperationPath>,
State(state): State<AppState>,
) -> Result<Json<Value>, ApiError> {
let operation = state
.service
.get_operation(&operation_id.as_str().into())
.get_operation(
&path.workspace_id.as_str().into(),
&path.operation_id.as_str().into(),
)
.await?;
Ok(Json(json!(operation)))
}
pub async fn get_operation_version(
Path((operation_id, version)): Path<(String, u32)>,
Path(path): Path<WorkspaceOperationVersionPath>,
State(state): State<AppState>,
) -> Result<Json<Value>, ApiError> {
let version = state
.service
.get_operation_version(&operation_id.as_str().into(), version)
.get_operation_version(
&path.workspace_id.as_str().into(),
&path.operation_id.as_str().into(),
path.version,
)
.await?;
Ok(Json(json!(version)))
}
pub async fn create_version(
Path(operation_id): Path<String>,
Path(path): Path<WorkspaceOperationPath>,
State(state): State<AppState>,
Json(payload): Json<NewVersionPayload>,
) -> Result<Json<Value>, ApiError> {
let created = state
.service
.create_version(&operation_id.as_str().into(), payload)
.create_version(
&path.workspace_id.as_str().into(),
&path.operation_id.as_str().into(),
payload,
)
.await?;
Ok(Json(json!(created)))
}
pub async fn publish_operation(
Path(operation_id): Path<String>,
Path(path): Path<WorkspaceOperationPath>,
State(state): State<AppState>,
Json(payload): Json<PublishPayload>,
) -> Result<Json<Value>, ApiError> {
let published = state
.service
.publish_operation(&operation_id.as_str().into(), payload.version)
.publish_operation(
&path.workspace_id.as_str().into(),
&path.operation_id.as_str().into(),
payload.version,
)
.await?;
Ok(Json(json!(published)))
}
pub async fn run_test(
Path(operation_id): Path<String>,
Path(path): Path<WorkspaceOperationPath>,
State(state): State<AppState>,
Json(payload): Json<TestRunPayload>,
) -> Result<Json<Value>, ApiError> {
let result = state
.service
.run_test(&operation_id.as_str().into(), payload)
.run_test(
&path.workspace_id.as_str().into(),
&path.operation_id.as_str().into(),
payload,
)
.await?;
Ok(Json(json!(result)))
}
pub async fn upload_input_json(
Path(operation_id): Path<String>,
Path(path): Path<WorkspaceOperationPath>,
State(state): State<AppState>,
Json(payload): Json<Value>,
) -> Result<Json<Value>, ApiError> {
let sample = state
.service
.save_json_sample(
&operation_id.as_str().into(),
&path.workspace_id.as_str().into(),
&path.operation_id.as_str().into(),
crank_registry::SampleKind::InputJson,
&payload,
)
@@ -109,14 +158,15 @@ pub async fn upload_input_json(
}
pub async fn upload_output_json(
Path(operation_id): Path<String>,
Path(path): Path<WorkspaceOperationPath>,
State(state): State<AppState>,
Json(payload): Json<Value>,
) -> Result<Json<Value>, ApiError> {
let sample = state
.service
.save_json_sample(
&operation_id.as_str().into(),
&path.workspace_id.as_str().into(),
&path.operation_id.as_str().into(),
crank_registry::SampleKind::OutputJson,
&payload,
)
@@ -130,7 +180,7 @@ pub async fn upload_output_json(
}
pub async fn upload_proto_descriptor(
Path(operation_id): Path<String>,
Path(path): Path<WorkspaceOperationPath>,
State(state): State<AppState>,
headers: HeaderMap,
body: Bytes,
@@ -139,7 +189,8 @@ pub async fn upload_proto_descriptor(
let descriptor = state
.service
.upload_proto_file(
&operation_id.as_str().into(),
&path.workspace_id.as_str().into(),
&path.operation_id.as_str().into(),
source_name.as_deref(),
body.as_ref(),
)
@@ -149,7 +200,7 @@ pub async fn upload_proto_descriptor(
}
pub async fn upload_descriptor_set(
Path(operation_id): Path<String>,
Path(path): Path<WorkspaceOperationPath>,
State(state): State<AppState>,
headers: HeaderMap,
body: Bytes,
@@ -158,7 +209,8 @@ pub async fn upload_descriptor_set(
let descriptor = state
.service
.upload_descriptor_set(
&operation_id.as_str().into(),
&path.workspace_id.as_str().into(),
&path.operation_id.as_str().into(),
source_name.as_deref(),
body.as_ref(),
)
@@ -168,37 +220,49 @@ pub async fn upload_descriptor_set(
}
pub async fn list_grpc_services(
Path(operation_id): Path<String>,
Path(path): Path<WorkspaceOperationPath>,
Query(query): Query<ExportQuery>,
State(state): State<AppState>,
) -> Result<Json<Value>, ApiError> {
let services = state
.service
.list_grpc_services(&operation_id.as_str().into(), query.version)
.list_grpc_services(
&path.workspace_id.as_str().into(),
&path.operation_id.as_str().into(),
query.version,
)
.await?;
Ok(Json(json!({ "services": services })))
}
pub async fn generate_draft(
Path(operation_id): Path<String>,
Path(path): Path<WorkspaceOperationPath>,
State(state): State<AppState>,
Json(payload): Json<GenerateDraftPayload>,
) -> Result<Json<Value>, ApiError> {
let draft = state
.service
.generate_draft(&operation_id.as_str().into(), payload)
.generate_draft(
&path.workspace_id.as_str().into(),
&path.operation_id.as_str().into(),
payload,
)
.await?;
Ok(Json(json!(draft)))
}
pub async fn export_operation(
Path(operation_id): Path<String>,
Path(path): Path<WorkspaceOperationPath>,
Query(query): Query<ExportQuery>,
State(state): State<AppState>,
) -> Result<impl IntoResponse, ApiError> {
let yaml = state
.service
.export_operation(&operation_id.as_str().into(), query)
.export_operation(
&path.workspace_id.as_str().into(),
&path.operation_id.as_str().into(),
query,
)
.await?;
let mut headers = HeaderMap::new();
headers.insert(
@@ -210,11 +274,15 @@ pub async fn export_operation(
}
pub async fn import_operation(
Path(path): Path<WorkspacePath>,
Query(query): Query<ImportQuery>,
State(state): State<AppState>,
body: String,
) -> Result<Json<Value>, ApiError> {
let imported = state.service.import_operation(query, &body).await?;
let imported = state
.service
.import_operation(&path.workspace_id.as_str().into(), query, &body)
.await?;
Ok(Json(json!(imported)))
}
+47
View File
@@ -0,0 +1,47 @@
use axum::{
Json,
extract::{Path, State},
};
use serde_json::{Value, json};
use crate::{
error::ApiError,
service::{UpdateWorkspacePayload, WorkspacePayload},
state::AppState,
};
pub async fn list_workspaces(State(state): State<AppState>) -> Result<Json<Value>, ApiError> {
let items = state.service.list_workspaces().await?;
Ok(Json(json!({ "items": items })))
}
pub async fn create_workspace(
State(state): State<AppState>,
Json(payload): Json<WorkspacePayload>,
) -> Result<Json<Value>, ApiError> {
let workspace = state.service.create_workspace(payload).await?;
Ok(Json(json!(workspace)))
}
pub async fn get_workspace(
Path(workspace_id): Path<String>,
State(state): State<AppState>,
) -> Result<Json<Value>, ApiError> {
let workspace = state
.service
.get_workspace(&workspace_id.as_str().into())
.await?;
Ok(Json(json!(workspace)))
}
pub async fn update_workspace(
Path(workspace_id): Path<String>,
State(state): State<AppState>,
Json(payload): Json<UpdateWorkspacePayload>,
) -> Result<Json<Value>, ApiError> {
let workspace = state
.service
.update_workspace(&workspace_id.as_str().into(), payload)
.await?;
Ok(Json(json!(workspace)))
}