Skip to main content

barbacane_compiler/spec_parser/
model.rs

1use serde::{Deserialize, Serialize};
2use std::collections::BTreeMap;
3
4/// A parsed API spec (OpenAPI or AsyncAPI).
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct ApiSpec {
7    /// Original filename (if parsed from file).
8    pub filename: Option<String>,
9    /// The format detected from the root field.
10    pub format: SpecFormat,
11    /// The spec version string (e.g. "3.1.0").
12    pub version: String,
13    /// The `info.title` field.
14    pub title: String,
15    /// The `info.version` field (API version, not spec version).
16    pub api_version: String,
17    /// Parsed path operations.
18    pub operations: Vec<Operation>,
19    /// Global middlewares from root-level `x-barbacane-middlewares`.
20    pub global_middlewares: Vec<MiddlewareConfig>,
21    /// Raw `x-barbacane-*` extensions at root level.
22    pub extensions: BTreeMap<String, serde_json::Value>,
23}
24
25/// Detected spec format.
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
27#[serde(rename_all = "lowercase")]
28pub enum SpecFormat {
29    OpenApi,
30    AsyncApi,
31}
32
33/// A single API operation (path + method for OpenAPI, channel + action for AsyncAPI).
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct Operation {
36    /// The path template (OpenAPI: "/users/{id}", AsyncAPI: channel address).
37    pub path: String,
38    /// The HTTP method (OpenAPI: "GET", AsyncAPI: "SEND"/"RECEIVE").
39    pub method: String,
40    /// The operationId, if present.
41    pub operation_id: Option<String>,
42    /// The operation summary (short description for MCP tool name).
43    #[serde(default)]
44    pub summary: Option<String>,
45    /// The operation description (detailed description for MCP tool).
46    #[serde(default)]
47    pub description: Option<String>,
48    /// Path/channel parameters defined on this operation.
49    pub parameters: Vec<Parameter>,
50    /// Request body definition (OpenAPI: requestBody, AsyncAPI: message payload for SEND).
51    pub request_body: Option<RequestBody>,
52    /// The dispatcher configuration from `x-barbacane-dispatch`.
53    pub dispatch: Option<DispatchConfig>,
54    /// Operation-level middlewares (replaces global chain if present).
55    pub middlewares: Option<Vec<MiddlewareConfig>>,
56    /// Whether this operation is deprecated (OpenAPI `deprecated` field).
57    #[serde(default)]
58    pub deprecated: bool,
59    /// Sunset date for deprecated operations (from `x-sunset` per RFC 8594).
60    /// Format: HTTP-date per RFC 9110 (e.g., "Sat, 31 Dec 2024 23:59:59 GMT").
61    pub sunset: Option<String>,
62    /// Operation-level `x-barbacane-*` extensions.
63    pub extensions: BTreeMap<String, serde_json::Value>,
64    /// AsyncAPI messages (for async operations only).
65    #[serde(default, skip_serializing_if = "Vec::is_empty")]
66    pub messages: Vec<Message>,
67    /// Protocol bindings (AsyncAPI: kafka, nats, mqtt, amqp, ws).
68    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
69    pub bindings: BTreeMap<String, serde_json::Value>,
70    /// Response definitions keyed by status code (e.g., "200", "201").
71    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
72    pub responses: BTreeMap<String, ResponseContent>,
73}
74
75/// Response content for a specific status code.
76#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct ResponseContent {
78    /// Content types and their schemas (e.g., "application/json" -> schema).
79    pub content: BTreeMap<String, ContentSchema>,
80}
81
82/// A path, query, or header parameter.
83#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct Parameter {
85    /// Parameter name.
86    pub name: String,
87    /// Location: "path", "query", "header".
88    pub location: String,
89    /// Whether this parameter is required.
90    pub required: bool,
91    /// The parameter's schema (for validation in M2).
92    pub schema: Option<serde_json::Value>,
93}
94
95/// Dispatcher configuration extracted from `x-barbacane-dispatch`.
96#[derive(Debug, Clone, Serialize, Deserialize)]
97pub struct DispatchConfig {
98    /// Plugin name (or name@version).
99    pub name: String,
100    /// Plugin-specific configuration.
101    #[serde(default)]
102    pub config: serde_json::Value,
103}
104
105/// Middleware configuration from `x-barbacane-middlewares`.
106#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct MiddlewareConfig {
108    /// Plugin name (or name@version).
109    pub name: String,
110    /// Plugin-specific configuration.
111    #[serde(default)]
112    pub config: serde_json::Value,
113}
114
115/// Request body definition from `requestBody`.
116#[derive(Debug, Clone, Serialize, Deserialize)]
117pub struct RequestBody {
118    /// Whether the request body is required.
119    pub required: bool,
120    /// Content types and their schemas (e.g., "application/json" -> schema).
121    pub content: BTreeMap<String, ContentSchema>,
122}
123
124/// Content schema for a specific media type.
125#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct ContentSchema {
127    /// The JSON Schema for this content type.
128    pub schema: Option<serde_json::Value>,
129}
130
131/// AsyncAPI message definition.
132#[derive(Debug, Clone, Serialize, Deserialize)]
133pub struct Message {
134    /// Message name/ID.
135    pub name: String,
136    /// Message payload schema.
137    pub payload: Option<serde_json::Value>,
138    /// Content type (e.g., "application/json").
139    pub content_type: Option<String>,
140    /// Protocol-specific bindings (kafka, nats, mqtt, amqp, ws, etc.).
141    #[serde(default)]
142    pub bindings: BTreeMap<String, serde_json::Value>,
143}
144
145/// AsyncAPI channel definition.
146#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct Channel {
148    /// Channel address/topic (e.g., "user/signedup", "orders.{orderId}").
149    pub address: String,
150    /// Messages that can be sent/received on this channel.
151    pub messages: Vec<Message>,
152    /// Channel parameters (for templated addresses like "orders.{orderId}").
153    pub parameters: Vec<Parameter>,
154    /// Protocol-specific bindings.
155    #[serde(default)]
156    pub bindings: BTreeMap<String, serde_json::Value>,
157}
158
159/// AsyncAPI operation action.
160#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
161#[serde(rename_all = "lowercase")]
162pub enum AsyncAction {
163    /// Gateway sends/publishes a message to the channel.
164    Send,
165    /// Gateway receives/subscribes to messages from the channel.
166    Receive,
167}
168
169impl std::fmt::Display for AsyncAction {
170    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171        match self {
172            AsyncAction::Send => write!(f, "SEND"),
173            AsyncAction::Receive => write!(f, "RECEIVE"),
174        }
175    }
176}