mockforge_http/handlers/
failure_designer.rs

1//! Failure Designer API handlers
2
3use axum::extract::{Path, Query, State};
4use axum::response::Json;
5use mockforge_chaos::failure_designer::{FailureDesignRule, FailureDesigner};
6use mockforge_chaos::ChaosScenario;
7use serde::{Deserialize, Serialize};
8use serde_json::{json, Value};
9use std::sync::Arc;
10
11/// Failure designer API state
12#[derive(Clone)]
13pub struct FailureDesignerState {
14    /// Failure designer instance
15    pub designer: Arc<FailureDesigner>,
16}
17
18impl FailureDesignerState {
19    /// Create new failure designer state
20    pub fn new() -> Self {
21        Self {
22            designer: Arc::new(FailureDesigner::new()),
23        }
24    }
25}
26
27impl Default for FailureDesignerState {
28    fn default() -> Self {
29        Self::new()
30    }
31}
32
33/// Request to validate a failure design rule
34#[derive(Debug, Deserialize)]
35pub struct ValidateRuleRequest {
36    /// Rule to validate
37    pub rule: FailureDesignRule,
38}
39
40/// Request to generate chaos scenario from rule
41#[derive(Debug, Deserialize)]
42pub struct GenerateScenarioRequest {
43    /// Rule to convert
44    pub rule: FailureDesignRule,
45}
46
47/// Response for rule validation
48#[derive(Debug, Serialize)]
49pub struct ValidateRuleResponse {
50    /// Success flag
51    pub success: bool,
52    /// Validation errors (if any)
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub error: Option<String>,
55}
56
57/// Response for scenario generation
58#[derive(Debug, Serialize)]
59pub struct GenerateScenarioResponse {
60    /// Success flag
61    pub success: bool,
62    /// Generated chaos scenario
63    pub scenario: ChaosScenario,
64    /// Route chaos configuration (JSON)
65    pub route_chaos_config: Value,
66    /// Webhook hook configuration (if applicable)
67    #[serde(skip_serializing_if = "Option::is_none")]
68    pub webhook_hook: Option<Value>,
69}
70
71/// Validate a failure design rule
72///
73/// POST /api/v1/chaos/failure-designer/validate
74pub async fn validate_rule(
75    State(state): State<FailureDesignerState>,
76    Json(request): Json<ValidateRuleRequest>,
77) -> Json<Value> {
78    let designer = &state.designer;
79    match designer.validate_rule(&request.rule) {
80        Ok(()) => Json(json!({
81            "success": true,
82        })),
83        Err(e) => Json(json!({
84            "success": false,
85            "error": e,
86        })),
87    }
88}
89
90/// Generate chaos scenario from failure design rule
91///
92/// POST /api/v1/chaos/failure-designer/generate
93pub async fn generate_scenario(
94    State(state): State<FailureDesignerState>,
95    Json(request): Json<GenerateScenarioRequest>,
96) -> Result<Json<Value>, String> {
97    let designer = &state.designer;
98
99    // Generate chaos scenario
100    let scenario = designer
101        .rule_to_scenario(&request.rule)
102        .map_err(|e| format!("Failed to generate scenario: {}", e))?;
103
104    // Generate route chaos config
105    let route_chaos_config = designer
106        .generate_route_chaos_config(&request.rule)
107        .map_err(|e| format!("Failed to generate route chaos config: {}", e))?;
108
109    // Generate webhook hook if applicable
110    let webhook_hook = if matches!(
111        request.rule.failure_type,
112        mockforge_chaos::failure_designer::FailureType::WebhookFailure { .. }
113    ) {
114        Some(
115            designer
116                .generate_webhook_hook(&request.rule)
117                .map_err(|e| format!("Failed to generate webhook hook: {}", e))?,
118        )
119    } else {
120        None
121    };
122
123    Ok(Json(json!({
124        "success": true,
125        "scenario": scenario,
126        "route_chaos_config": route_chaos_config,
127        "webhook_hook": webhook_hook,
128    })))
129}
130
131/// Preview generated configuration
132///
133/// POST /api/v1/chaos/failure-designer/preview
134pub async fn preview_config(
135    State(state): State<FailureDesignerState>,
136    Json(request): Json<GenerateScenarioRequest>,
137) -> Result<Json<Value>, String> {
138    let designer = &state.designer;
139
140    // Validate rule first
141    designer
142        .validate_rule(&request.rule)
143        .map_err(|e| format!("Validation failed: {}", e))?;
144
145    // Generate all configurations
146    let scenario = designer
147        .rule_to_scenario(&request.rule)
148        .map_err(|e| format!("Failed to generate scenario: {}", e))?;
149
150    let route_chaos_config = designer
151        .generate_route_chaos_config(&request.rule)
152        .map_err(|e| format!("Failed to generate route chaos config: {}", e))?;
153
154    let webhook_hook = if matches!(
155        request.rule.failure_type,
156        mockforge_chaos::failure_designer::FailureType::WebhookFailure { .. }
157    ) {
158        Some(
159            designer
160                .generate_webhook_hook(&request.rule)
161                .map_err(|e| format!("Failed to generate webhook hook: {}", e))?,
162        )
163    } else {
164        None
165    };
166
167    Ok(Json(json!({
168        "success": true,
169        "rule": request.rule,
170        "scenario": scenario,
171        "route_chaos_config": route_chaos_config,
172        "webhook_hook": webhook_hook,
173    })))
174}