re-uploading work
This commit is contained in:
410
crates/api/src/openapi.rs
Normal file
410
crates/api/src/openapi.rs
Normal file
@@ -0,0 +1,410 @@
|
||||
//! OpenAPI specification and documentation
|
||||
|
||||
use utoipa::{
|
||||
openapi::security::{HttpAuthScheme, HttpBuilder, SecurityScheme},
|
||||
Modify, OpenApi,
|
||||
};
|
||||
|
||||
use crate::dto::{
|
||||
action::{
|
||||
ActionResponse, ActionSummary, CreateActionRequest, QueueStatsResponse, UpdateActionRequest,
|
||||
},
|
||||
auth::{
|
||||
ChangePasswordRequest, CurrentUserResponse, LoginRequest, RefreshTokenRequest,
|
||||
RegisterRequest, TokenResponse,
|
||||
},
|
||||
common::{ApiResponse, PaginatedResponse, PaginationMeta, SuccessResponse},
|
||||
event::{EnforcementResponse, EnforcementSummary, EventResponse, EventSummary},
|
||||
execution::{ExecutionResponse, ExecutionSummary},
|
||||
inquiry::{
|
||||
CreateInquiryRequest, InquiryRespondRequest, InquiryResponse, InquirySummary,
|
||||
UpdateInquiryRequest,
|
||||
},
|
||||
key::{CreateKeyRequest, KeyResponse, KeySummary, UpdateKeyRequest},
|
||||
pack::{
|
||||
CreatePackRequest, InstallPackRequest, PackInstallResponse, PackResponse, PackSummary,
|
||||
PackWorkflowSyncResponse, PackWorkflowValidationResponse, RegisterPackRequest,
|
||||
UpdatePackRequest, WorkflowSyncResult,
|
||||
},
|
||||
rule::{CreateRuleRequest, RuleResponse, RuleSummary, UpdateRuleRequest},
|
||||
trigger::{
|
||||
CreateSensorRequest, CreateTriggerRequest, SensorResponse, SensorSummary, TriggerResponse,
|
||||
TriggerSummary, UpdateSensorRequest, UpdateTriggerRequest,
|
||||
},
|
||||
webhook::{WebhookReceiverRequest, WebhookReceiverResponse},
|
||||
workflow::{CreateWorkflowRequest, UpdateWorkflowRequest, WorkflowResponse, WorkflowSummary},
|
||||
};
|
||||
|
||||
/// OpenAPI documentation structure
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
info(
|
||||
title = "Attune API",
|
||||
version = "0.1.0",
|
||||
description = "Event-driven automation and orchestration platform API",
|
||||
contact(
|
||||
name = "Attune Team",
|
||||
url = "https://github.com/yourusername/attune"
|
||||
),
|
||||
license(
|
||||
name = "MIT",
|
||||
url = "https://opensource.org/licenses/MIT"
|
||||
)
|
||||
),
|
||||
servers(
|
||||
(url = "http://localhost:8080", description = "Local development server"),
|
||||
(url = "https://api.attune.example.com", description = "Production server")
|
||||
),
|
||||
paths(
|
||||
// Health check
|
||||
crate::routes::health::health,
|
||||
crate::routes::health::health_detailed,
|
||||
crate::routes::health::readiness,
|
||||
crate::routes::health::liveness,
|
||||
|
||||
// Authentication
|
||||
crate::routes::auth::login,
|
||||
crate::routes::auth::register,
|
||||
crate::routes::auth::refresh_token,
|
||||
crate::routes::auth::get_current_user,
|
||||
crate::routes::auth::change_password,
|
||||
|
||||
// Packs
|
||||
crate::routes::packs::list_packs,
|
||||
crate::routes::packs::get_pack,
|
||||
crate::routes::packs::create_pack,
|
||||
crate::routes::packs::update_pack,
|
||||
crate::routes::packs::delete_pack,
|
||||
crate::routes::packs::register_pack,
|
||||
crate::routes::packs::install_pack,
|
||||
crate::routes::packs::sync_pack_workflows,
|
||||
crate::routes::packs::validate_pack_workflows,
|
||||
crate::routes::packs::test_pack,
|
||||
crate::routes::packs::get_pack_test_history,
|
||||
crate::routes::packs::get_pack_latest_test,
|
||||
|
||||
// Actions
|
||||
crate::routes::actions::list_actions,
|
||||
crate::routes::actions::list_actions_by_pack,
|
||||
crate::routes::actions::get_action,
|
||||
crate::routes::actions::create_action,
|
||||
crate::routes::actions::update_action,
|
||||
crate::routes::actions::delete_action,
|
||||
crate::routes::actions::get_queue_stats,
|
||||
|
||||
// Triggers
|
||||
crate::routes::triggers::list_triggers,
|
||||
crate::routes::triggers::list_enabled_triggers,
|
||||
crate::routes::triggers::list_triggers_by_pack,
|
||||
crate::routes::triggers::get_trigger,
|
||||
crate::routes::triggers::create_trigger,
|
||||
crate::routes::triggers::update_trigger,
|
||||
crate::routes::triggers::delete_trigger,
|
||||
crate::routes::triggers::enable_trigger,
|
||||
crate::routes::triggers::disable_trigger,
|
||||
|
||||
// Sensors
|
||||
crate::routes::triggers::list_sensors,
|
||||
crate::routes::triggers::list_enabled_sensors,
|
||||
crate::routes::triggers::list_sensors_by_pack,
|
||||
crate::routes::triggers::list_sensors_by_trigger,
|
||||
crate::routes::triggers::get_sensor,
|
||||
crate::routes::triggers::create_sensor,
|
||||
crate::routes::triggers::update_sensor,
|
||||
crate::routes::triggers::delete_sensor,
|
||||
crate::routes::triggers::enable_sensor,
|
||||
crate::routes::triggers::disable_sensor,
|
||||
|
||||
// Rules
|
||||
crate::routes::rules::list_rules,
|
||||
crate::routes::rules::list_enabled_rules,
|
||||
crate::routes::rules::list_rules_by_pack,
|
||||
crate::routes::rules::list_rules_by_action,
|
||||
crate::routes::rules::list_rules_by_trigger,
|
||||
crate::routes::rules::get_rule,
|
||||
crate::routes::rules::create_rule,
|
||||
crate::routes::rules::update_rule,
|
||||
crate::routes::rules::delete_rule,
|
||||
crate::routes::rules::enable_rule,
|
||||
crate::routes::rules::disable_rule,
|
||||
|
||||
// Executions
|
||||
crate::routes::executions::list_executions,
|
||||
crate::routes::executions::get_execution,
|
||||
crate::routes::executions::list_executions_by_status,
|
||||
crate::routes::executions::list_executions_by_enforcement,
|
||||
crate::routes::executions::get_execution_stats,
|
||||
|
||||
// Events
|
||||
crate::routes::events::list_events,
|
||||
crate::routes::events::get_event,
|
||||
|
||||
// Enforcements
|
||||
crate::routes::events::list_enforcements,
|
||||
crate::routes::events::get_enforcement,
|
||||
|
||||
// Inquiries
|
||||
crate::routes::inquiries::list_inquiries,
|
||||
crate::routes::inquiries::get_inquiry,
|
||||
crate::routes::inquiries::list_inquiries_by_status,
|
||||
crate::routes::inquiries::list_inquiries_by_execution,
|
||||
crate::routes::inquiries::create_inquiry,
|
||||
crate::routes::inquiries::update_inquiry,
|
||||
crate::routes::inquiries::respond_to_inquiry,
|
||||
crate::routes::inquiries::delete_inquiry,
|
||||
|
||||
// Keys/Secrets
|
||||
crate::routes::keys::list_keys,
|
||||
crate::routes::keys::get_key,
|
||||
crate::routes::keys::create_key,
|
||||
crate::routes::keys::update_key,
|
||||
crate::routes::keys::delete_key,
|
||||
|
||||
// Workflows
|
||||
crate::routes::workflows::list_workflows,
|
||||
crate::routes::workflows::list_workflows_by_pack,
|
||||
crate::routes::workflows::get_workflow,
|
||||
crate::routes::workflows::create_workflow,
|
||||
crate::routes::workflows::update_workflow,
|
||||
crate::routes::workflows::delete_workflow,
|
||||
|
||||
// Webhooks
|
||||
crate::routes::webhooks::enable_webhook,
|
||||
crate::routes::webhooks::disable_webhook,
|
||||
crate::routes::webhooks::regenerate_webhook_key,
|
||||
crate::routes::webhooks::receive_webhook,
|
||||
),
|
||||
components(
|
||||
schemas(
|
||||
// Common types
|
||||
ApiResponse<TokenResponse>,
|
||||
ApiResponse<CurrentUserResponse>,
|
||||
ApiResponse<PackResponse>,
|
||||
ApiResponse<PackInstallResponse>,
|
||||
ApiResponse<ActionResponse>,
|
||||
ApiResponse<TriggerResponse>,
|
||||
ApiResponse<SensorResponse>,
|
||||
ApiResponse<RuleResponse>,
|
||||
ApiResponse<ExecutionResponse>,
|
||||
ApiResponse<EventResponse>,
|
||||
ApiResponse<EnforcementResponse>,
|
||||
ApiResponse<InquiryResponse>,
|
||||
ApiResponse<KeyResponse>,
|
||||
ApiResponse<WorkflowResponse>,
|
||||
ApiResponse<QueueStatsResponse>,
|
||||
PaginatedResponse<PackSummary>,
|
||||
PaginatedResponse<ActionSummary>,
|
||||
PaginatedResponse<TriggerSummary>,
|
||||
PaginatedResponse<SensorSummary>,
|
||||
PaginatedResponse<RuleSummary>,
|
||||
PaginatedResponse<ExecutionSummary>,
|
||||
PaginatedResponse<EventSummary>,
|
||||
PaginatedResponse<EnforcementSummary>,
|
||||
PaginatedResponse<InquirySummary>,
|
||||
PaginatedResponse<KeySummary>,
|
||||
PaginatedResponse<WorkflowSummary>,
|
||||
PaginationMeta,
|
||||
SuccessResponse,
|
||||
|
||||
// Auth DTOs
|
||||
LoginRequest,
|
||||
RegisterRequest,
|
||||
RefreshTokenRequest,
|
||||
ChangePasswordRequest,
|
||||
TokenResponse,
|
||||
CurrentUserResponse,
|
||||
|
||||
// Pack DTOs
|
||||
CreatePackRequest,
|
||||
UpdatePackRequest,
|
||||
RegisterPackRequest,
|
||||
InstallPackRequest,
|
||||
PackResponse,
|
||||
PackSummary,
|
||||
PackInstallResponse,
|
||||
PackWorkflowSyncResponse,
|
||||
PackWorkflowValidationResponse,
|
||||
WorkflowSyncResult,
|
||||
attune_common::models::pack_test::PackTestResult,
|
||||
attune_common::models::pack_test::PackTestExecution,
|
||||
attune_common::models::pack_test::TestSuiteResult,
|
||||
attune_common::models::pack_test::TestCaseResult,
|
||||
attune_common::models::pack_test::TestStatus,
|
||||
attune_common::models::pack_test::PackTestSummary,
|
||||
PaginatedResponse<attune_common::models::pack_test::PackTestSummary>,
|
||||
|
||||
// Action DTOs
|
||||
CreateActionRequest,
|
||||
UpdateActionRequest,
|
||||
ActionResponse,
|
||||
ActionSummary,
|
||||
QueueStatsResponse,
|
||||
|
||||
// Trigger DTOs
|
||||
CreateTriggerRequest,
|
||||
UpdateTriggerRequest,
|
||||
TriggerResponse,
|
||||
TriggerSummary,
|
||||
|
||||
// Sensor DTOs
|
||||
CreateSensorRequest,
|
||||
UpdateSensorRequest,
|
||||
SensorResponse,
|
||||
SensorSummary,
|
||||
|
||||
// Rule DTOs
|
||||
CreateRuleRequest,
|
||||
UpdateRuleRequest,
|
||||
RuleResponse,
|
||||
RuleSummary,
|
||||
|
||||
// Execution DTOs
|
||||
ExecutionResponse,
|
||||
ExecutionSummary,
|
||||
|
||||
// Event DTOs
|
||||
EventResponse,
|
||||
EventSummary,
|
||||
|
||||
// Enforcement DTOs
|
||||
EnforcementResponse,
|
||||
EnforcementSummary,
|
||||
|
||||
// Inquiry DTOs
|
||||
CreateInquiryRequest,
|
||||
UpdateInquiryRequest,
|
||||
InquiryRespondRequest,
|
||||
InquiryResponse,
|
||||
InquirySummary,
|
||||
|
||||
// Key/Secret DTOs
|
||||
CreateKeyRequest,
|
||||
UpdateKeyRequest,
|
||||
KeyResponse,
|
||||
KeySummary,
|
||||
|
||||
// Workflow DTOs
|
||||
CreateWorkflowRequest,
|
||||
UpdateWorkflowRequest,
|
||||
WorkflowResponse,
|
||||
WorkflowSummary,
|
||||
|
||||
// Webhook DTOs
|
||||
WebhookReceiverRequest,
|
||||
WebhookReceiverResponse,
|
||||
ApiResponse<WebhookReceiverResponse>,
|
||||
)
|
||||
),
|
||||
modifiers(&SecurityAddon),
|
||||
tags(
|
||||
(name = "health", description = "Health check endpoints"),
|
||||
(name = "auth", description = "Authentication and authorization endpoints"),
|
||||
(name = "packs", description = "Pack management endpoints"),
|
||||
(name = "actions", description = "Action management endpoints"),
|
||||
(name = "triggers", description = "Trigger management endpoints"),
|
||||
(name = "sensors", description = "Sensor management endpoints"),
|
||||
(name = "rules", description = "Rule management endpoints"),
|
||||
(name = "executions", description = "Execution query endpoints"),
|
||||
(name = "inquiries", description = "Inquiry (human-in-the-loop) endpoints"),
|
||||
(name = "events", description = "Event query endpoints"),
|
||||
(name = "enforcements", description = "Enforcement query endpoints"),
|
||||
(name = "secrets", description = "Secret management endpoints"),
|
||||
(name = "workflows", description = "Workflow management endpoints"),
|
||||
(name = "webhooks", description = "Webhook management and receiver endpoints"),
|
||||
)
|
||||
)]
|
||||
pub struct ApiDoc;
|
||||
|
||||
/// Security scheme modifier to add JWT Bearer authentication
|
||||
struct SecurityAddon;
|
||||
|
||||
impl Modify for SecurityAddon {
|
||||
fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
|
||||
if let Some(components) = openapi.components.as_mut() {
|
||||
components.add_security_scheme(
|
||||
"bearer_auth",
|
||||
SecurityScheme::Http(
|
||||
HttpBuilder::new()
|
||||
.scheme(HttpAuthScheme::Bearer)
|
||||
.bearer_format("JWT")
|
||||
.description(Some(
|
||||
"JWT access token obtained from /auth/login or /auth/register",
|
||||
))
|
||||
.build(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_openapi_spec_generation() {
|
||||
let doc = ApiDoc::openapi();
|
||||
|
||||
// Verify basic info
|
||||
assert_eq!(doc.info.title, "Attune API");
|
||||
assert_eq!(doc.info.version, "0.1.0");
|
||||
|
||||
// Verify we have components
|
||||
assert!(doc.components.is_some());
|
||||
|
||||
// Verify we have security schemes
|
||||
let components = doc.components.unwrap();
|
||||
assert!(components.security_schemes.contains_key("bearer_auth"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_openapi_endpoint_count() {
|
||||
let doc = ApiDoc::openapi();
|
||||
|
||||
// Count all paths in the OpenAPI spec
|
||||
let path_count = doc.paths.paths.len();
|
||||
|
||||
// Count all operations (methods on paths)
|
||||
let operation_count: usize = doc
|
||||
.paths
|
||||
.paths
|
||||
.values()
|
||||
.map(|path_item| {
|
||||
let mut count = 0;
|
||||
if path_item.get.is_some() {
|
||||
count += 1;
|
||||
}
|
||||
if path_item.post.is_some() {
|
||||
count += 1;
|
||||
}
|
||||
if path_item.put.is_some() {
|
||||
count += 1;
|
||||
}
|
||||
if path_item.delete.is_some() {
|
||||
count += 1;
|
||||
}
|
||||
if path_item.patch.is_some() {
|
||||
count += 1;
|
||||
}
|
||||
count
|
||||
})
|
||||
.sum();
|
||||
|
||||
// We have 57 unique paths with 81 total operations (HTTP methods)
|
||||
// This test ensures we don't accidentally remove endpoints
|
||||
assert!(
|
||||
path_count >= 57,
|
||||
"Expected at least 57 unique API paths, found {}",
|
||||
path_count
|
||||
);
|
||||
|
||||
assert!(
|
||||
operation_count >= 81,
|
||||
"Expected at least 81 API operations, found {}",
|
||||
operation_count
|
||||
);
|
||||
|
||||
println!("Total API paths: {}", path_count);
|
||||
println!("Total API operations: {}", operation_count);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user