#!/usr/bin/env nu # API Routes and handlers for Provisioning System # Defines all REST API endpoints and their handlers use ../lib_provisioning/utils/settings.nu * use ../main_provisioning/query.nu * # Route definitions for the API server export def get_route_definitions []: nothing -> list { [ { method: "GET" path: "/api/v1/health" handler: "health_check" description: "Health check endpoint" parameters: [] } { method: "GET" path: "/api/v1/query" handler: "query_infrastructure" description: "Query infrastructure state" parameters: [ { name: "target", type: "string", required: false, default: "servers", description: "Query target (servers, metrics, logs)" } { name: "infra", type: "string", required: false, description: "Infrastructure name" } { name: "provider", type: "string", required: false, description: "Provider filter" } { name: "find", type: "string", required: false, description: "Search filter" } { name: "format", type: "string", required: false, default: "json", description: "Output format" } ] } { method: "POST" path: "/api/v1/query" handler: "complex_query" description: "Execute complex queries with request body" body_schema: { type: "object" properties: { query_type: { type: "string", enum: ["infrastructure", "metrics", "logs", "ai"] } target: { type: "string" } filters: { type: "object" } ai_query: { type: "string", description: "Natural language query" } aggregations: { type: "array" } } } } { method: "GET" path: "/api/v1/metrics" handler: "get_metrics" description: "Retrieve system metrics" parameters: [ { name: "timerange", type: "string", default: "1h", description: "Time range (1m, 5m, 1h, 1d)" } { name: "metric_type", type: "string", description: "Metric type filter" } { name: "aggregation", type: "string", default: "avg", description: "Aggregation method" } ] } { method: "GET" path: "/api/v1/logs" handler: "get_logs" description: "Retrieve system logs" parameters: [ { name: "level", type: "string", default: "info", description: "Log level filter" } { name: "service", type: "string", description: "Service name filter" } { name: "since", type: "string", default: "1h", description: "Time since" } { name: "limit", type: "integer", default: 100, description: "Number of entries" } ] } { method: "GET" path: "/api/v1/dashboard" handler: "get_dashboard_data" description: "Dashboard data endpoint" parameters: [ { name: "view", type: "string", default: "overview", description: "Dashboard view" } { name: "refresh", type: "boolean", default: false, description: "Force refresh" } ] } { method: "GET" path: "/api/v1/servers" handler: "list_servers" description: "List all servers" parameters: [ { name: "status", type: "string", description: "Status filter" } { name: "provider", type: "string", description: "Provider filter" } { name: "infra", type: "string", description: "Infrastructure filter" } ] } { method: "GET" path: "/api/v1/servers/{id}" handler: "get_server" description: "Get specific server details" path_params: [ { name: "id", type: "string", required: true, description: "Server ID" } ] } { method: "GET" path: "/api/v1/servers/{id}/status" handler: "get_server_status" description: "Get server status and metrics" path_params: [ { name: "id", type: "string", required: true, description: "Server ID" } ] } { method: "GET" path: "/api/v1/servers/{id}/logs" handler: "get_server_logs" description: "Get server-specific logs" path_params: [ { name: "id", type: "string", required: true, description: "Server ID" } ] } { method: "POST" path: "/api/v1/servers" handler: "create_server" description: "Create new server" body_schema: { type: "object" required: ["name", "provider"] properties: { name: { type: "string" } provider: { type: "string" } infra: { type: "string" } instance_type: { type: "string" } count: { type: "integer", default: 1 } } } } { method: "DELETE" path: "/api/v1/servers/{id}" handler: "delete_server" description: "Delete server" path_params: [ { name: "id", type: "string", required: true, description: "Server ID" } ] } { method: "GET" path: "/api/v1/ai/query" handler: "ai_query" description: "Natural language infrastructure queries" parameters: [ { name: "q", type: "string", required: true, description: "Natural language query" } { name: "context", type: "string", description: "Context for the query" } ] } { method: "POST" path: "/api/v1/ai/analyze" handler: "ai_analyze" description: "AI-powered infrastructure analysis" body_schema: { type: "object" properties: { analysis_type: { type: "string", enum: ["cost", "performance", "security", "optimization"] } timerange: { type: "string", default: "24h" } target: { type: "string" } } } } { method: "GET" path: "/api/v1/dataframes/query" handler: "dataframe_query" description: "Query infrastructure data using dataframes" parameters: [ { name: "source", type: "string", required: true, description: "Data source (logs, metrics, events)" } { name: "query", type: "string", required: true, description: "Polars/SQL-like query" } { name: "format", type: "string", default: "json", description: "Output format" } ] } { method: "WebSocket" path: "/ws/stream" handler: "websocket_stream" description: "Real-time updates via WebSocket" parameters: [ { name: "subscribe", type: "array", description: "Subscription topics" } ] } ] } # Generate OpenAPI/Swagger specification export def generate_api_spec []: nothing -> record { let routes = get_route_definitions { openapi: "3.0.3" info: { title: "Provisioning System API" description: "REST API for infrastructure provisioning and management" version: "1.0.0" contact: { name: "Provisioning Team" url: "https://github.com/provisioning-rs" } } servers: [ { url: "http://localhost:8080" description: "Development server" } ] paths: ($routes | generate_paths) components: { schemas: (generate_schemas) securitySchemes: { BearerAuth: { type: "http" scheme: "bearer" } } } security: [ { BearerAuth: [] } ] } } def generate_paths []: list -> record { let paths = {} $in | each { |route| let path_key = ($route.path | str replace -a "{id}" "{id}") $paths | insert $path_key { ($route.method | str downcase): { summary: $route.description parameters: ($route.parameters? | default [] | each { |param| { name: $param.name in: "query" required: ($param.required? | default false) schema: { type: $param.type } description: $param.description? } }) responses: { "200": { description: "Successful response" content: { "application/json": { schema: { type: "object" } } } } "400": { description: "Bad request" } "500": { description: "Internal server error" } } } } } | last } def generate_schemas []: nothing -> record { { Error: { type: "object" properties: { error: { type: "string" } message: { type: "string" } code: { type: "integer" } } } HealthCheck: { type: "object" properties: { status: { type: "string" } service: { type: "string" } version: { type: "string" } timestamp: { type: "string" } } } Server: { type: "object" properties: { id: { type: "string" } name: { type: "string" } provider: { type: "string" } status: { type: "string" } ip_address: { type: "string" } created_at: { type: "string" } } } Metrics: { type: "object" properties: { timestamp: { type: "string" } cpu_usage: { type: "number" } memory_usage: { type: "number" } disk_usage: { type: "number" } network_io: { type: "object" } } } LogEntry: { type: "object" properties: { timestamp: { type: "string" } level: { type: "string" } service: { type: "string" } message: { type: "string" } metadata: { type: "object" } } } } } # Generate route documentation export def generate_route_docs []: nothing -> str { let routes = get_route_definitions let header = "# Provisioning API Routes\n\nThis document describes all available API endpoints.\n\n" let route_docs = ($routes | each { |route| let params_doc = if ($route.parameters? | length) > 0 { "\n**Parameters:**\n" + ($route.parameters | each { |p| $"- `($p.name)` \\(($p.type)\\): ($p.description? | default 'No description')" } | str join "\n") } else { "" } let body_doc = if ($route.body_schema? | is-not-empty) { $"\n**Request Body:**\n```json\n($route.body_schema | to json)\n```" } else { "" } $"## ($route.method) ($route.path)\n\n($route.description)($params_doc)($body_doc)\n" } | str join "\n") $header + $route_docs } # Validate route configuration export def validate_routes []: nothing -> record { let routes = get_route_definitions let validation_results = [] let path_conflicts = ($routes | group-by path | each { |path, group| if ($group | length) > 1 { let methods = ($group | get method) let duplicate_methods = ($methods | uniq | length) != ($methods | length) if $duplicate_methods { { path: $path, issue: "duplicate_methods", methods: $methods } } } } | compact) { total_routes: ($routes | length) unique_paths: ($routes | get path | uniq | length) path_conflicts: $path_conflicts validation_passed: ($path_conflicts | length) == 0 } }