use axum::{ Json, extract::{Extension, Path, Query, State}, http::{HeaderMap, StatusCode, header}, response::IntoResponse, }; use serde::Deserialize; use serde_json::{Value, json}; use crate::{ error::ApiError, request_context::RequestContext, service::{ ExportQuery, GenerateDraftPayload, ImportQuery, NewVersionPayload, OperationPayload, PublishPayload, TestRunPayload, UpdateOperationPayload, }, state::AppState, }; #[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, State(state): State, ) -> Result, ApiError> { let items = state .service .list_operations(&path.workspace_id.as_str().into()) .await?; let total = items.len(); Ok(Json(json!({ "items": items, "page": 1, "page_size": total, "total": total }))) } pub async fn create_operation( Path(path): Path, State(state): State, Json(payload): Json, ) -> Result, ApiError> { let created = state .service .create_operation(&path.workspace_id.as_str().into(), payload) .await?; Ok(Json(json!(created))) } pub async fn get_operation( Path(path): Path, State(state): State, ) -> Result, ApiError> { let operation = state .service .get_operation( &path.workspace_id.as_str().into(), &path.operation_id.as_str().into(), ) .await?; Ok(Json(json!(operation))) } pub async fn update_operation( Path(path): Path, State(state): State, Json(payload): Json, ) -> Result, ApiError> { let result = state .service .update_operation( &path.workspace_id.as_str().into(), &path.operation_id.as_str().into(), payload, ) .await?; Ok(Json(json!(result))) } pub async fn delete_operation( Path(path): Path, State(state): State, ) -> Result, ApiError> { let result = state .service .delete_operation( &path.workspace_id.as_str().into(), &path.operation_id.as_str().into(), ) .await?; Ok(Json(json!(result))) } pub async fn get_operation_version( Path(path): Path, State(state): State, ) -> Result, ApiError> { let version = state .service .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(path): Path, State(state): State, Json(payload): Json, ) -> Result, ApiError> { let created = state .service .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(path): Path, State(state): State, Json(payload): Json, ) -> Result, ApiError> { let published = state .service .publish_operation( &path.workspace_id.as_str().into(), &path.operation_id.as_str().into(), payload.version, ) .await?; Ok(Json(json!(published))) } pub async fn archive_operation( Path(path): Path, State(state): State, ) -> Result, ApiError> { let archived = state .service .archive_operation( &path.workspace_id.as_str().into(), &path.operation_id.as_str().into(), ) .await?; Ok(Json(json!(archived))) } pub async fn run_test( Path(path): Path, State(state): State, Extension(request_context): Extension, Json(payload): Json, ) -> Result, ApiError> { let result = state .service .run_test( &path.workspace_id.as_str().into(), &path.operation_id.as_str().into(), payload, &request_context.request_id, ) .await?; Ok(Json(json!(result))) } pub async fn upload_input_json( Path(path): Path, State(state): State, Json(payload): Json, ) -> Result, ApiError> { let sample = state .service .save_json_sample( &path.workspace_id.as_str().into(), &path.operation_id.as_str().into(), crank_registry::SampleKind::InputJson, &payload, ) .await?; Ok(Json(json!({ "sample_id": sample.id.as_str(), "sample_kind": sample.sample_kind, "version": sample.version }))) } pub async fn upload_output_json( Path(path): Path, State(state): State, Json(payload): Json, ) -> Result, ApiError> { let sample = state .service .save_json_sample( &path.workspace_id.as_str().into(), &path.operation_id.as_str().into(), crank_registry::SampleKind::OutputJson, &payload, ) .await?; Ok(Json(json!({ "sample_id": sample.id.as_str(), "sample_kind": sample.sample_kind, "version": sample.version }))) } pub async fn generate_draft( Path(path): Path, State(state): State, Json(payload): Json, ) -> Result, ApiError> { let draft = state .service .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(path): Path, Query(query): Query, State(state): State, ) -> Result { let yaml = state .service .export_operation( &path.workspace_id.as_str().into(), &path.operation_id.as_str().into(), query, ) .await?; let mut headers = HeaderMap::new(); headers.insert( header::CONTENT_TYPE, header::HeaderValue::from_static("application/yaml"), ); Ok((StatusCode::OK, headers, yaml)) } pub async fn import_operation( Path(path): Path, Query(query): Query, State(state): State, body: String, ) -> Result, ApiError> { let imported = state .service .import_operation(&path.workspace_id.as_str().into(), query, &body) .await?; Ok(Json(json!(imported))) }