use asyncapi_rust::{
AsyncApiSpec, Channel, Components, Info, Message, Operation, OperationAction, Server,
ToAsyncApiMessage, schemars::JsonSchema,
};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToAsyncApiMessage)]
#[serde(tag = "type")]
pub enum ChatMessage {
#[serde(rename = "user.join")]
#[asyncapi(
summary = "User joins a chat room",
description = "Sent when a user successfully joins a chat room"
)]
UserJoin {
username: String,
room: String,
},
#[serde(rename = "user.leave")]
#[asyncapi(
summary = "User leaves a chat room",
description = "Sent when a user exits a chat room"
)]
UserLeave {
username: String,
room: String,
},
#[serde(rename = "chat.message")]
#[asyncapi(
summary = "Send a chat message",
description = "Broadcast a message to all users in a chat room"
)]
Chat {
username: String,
room: String,
text: String,
timestamp: u64,
},
#[serde(rename = "user.typing")]
#[asyncapi(
summary = "User typing indicator",
description = "Real-time indication that a user is composing a message"
)]
Typing {
username: String,
room: String,
},
}
fn main() {
println!("🚀 Generating AsyncAPI specification for Chat WebSocket API\n");
println!("📋 Message types discovered:");
for (i, name) in ChatMessage::asyncapi_message_names().iter().enumerate() {
println!(" {}. {}", i + 1, name);
}
println!();
println!("🔧 Generating JSON schemas...");
let messages = ChatMessage::asyncapi_messages();
println!(" Generated {} message schemas\n", messages.len());
let spec = build_asyncapi_spec(messages);
let json = serde_json::to_string_pretty(&spec).expect("Failed to serialize spec");
println!("📄 Complete AsyncAPI 3.0 Specification:\n");
println!("{}", json);
println!();
println!("📊 Statistics:");
println!(" Version: {}", spec.asyncapi);
println!(" Title: {}", spec.info.title);
println!(" API Version: {}", spec.info.version);
if let Some(channels) = &spec.channels {
println!(" Channels: {}", channels.len());
}
if let Some(operations) = &spec.operations {
println!(" Operations: {}", operations.len());
}
if let Some(components) = &spec.components {
if let Some(msgs) = &components.messages {
println!(" Messages: {}", msgs.len());
}
}
}
fn build_asyncapi_spec(messages: Vec<Message>) -> AsyncApiSpec {
let mut servers = HashMap::new();
servers.insert(
"production".to_string(),
Server {
host: "api.example.com".to_string(),
protocol: "wss".to_string(),
pathname: None,
description: Some("Production WebSocket server".to_string()),
variables: None,
},
);
let mut channels = HashMap::new();
channels.insert(
"chat".to_string(),
Channel {
address: Some("/ws/chat".to_string()),
messages: None, parameters: None,
},
);
let mut operations = HashMap::new();
operations.insert(
"sendMessage".to_string(),
Operation {
action: OperationAction::Send,
channel: asyncapi_rust::ChannelRef {
reference: "#/channels/chat".to_string(),
},
messages: Some(
messages
.iter()
.enumerate()
.map(|(i, msg)| asyncapi_rust::MessageRef::Reference {
reference: format!(
"#/components/messages/{}",
msg.name.as_ref().unwrap_or(&format!("message_{}", i))
),
})
.collect(),
),
},
);
operations.insert(
"receiveMessage".to_string(),
Operation {
action: OperationAction::Receive,
channel: asyncapi_rust::ChannelRef {
reference: "#/channels/chat".to_string(),
},
messages: Some(
messages
.iter()
.enumerate()
.map(|(i, msg)| asyncapi_rust::MessageRef::Reference {
reference: format!(
"#/components/messages/{}",
msg.name.as_ref().unwrap_or(&format!("message_{}", i))
),
})
.collect(),
),
},
);
let mut component_messages = HashMap::new();
for message in messages {
if let Some(name) = &message.name {
component_messages.insert(name.clone(), message);
}
}
let components = Components {
messages: Some(component_messages),
schemas: None,
};
AsyncApiSpec {
asyncapi: "3.0.0".to_string(),
info: Info {
title: "Chat WebSocket API".to_string(),
version: "1.0.0".to_string(),
description: Some(
"Real-time chat application using WebSocket for bidirectional communication"
.to_string(),
),
},
servers: Some(servers),
channels: Some(channels),
operations: Some(operations),
components: Some(components),
}
}