server_less/lib.rs
1//! Server-less - Composable derive macros for Rust
2//!
3//! Server-less takes an **impl-first** approach: write your Rust methods,
4//! and derive macros project them into various protocols (HTTP, CLI, MCP, WebSocket).
5//!
6//! # Quick Start
7//!
8//! ```ignore
9//! use server_less::prelude::*;
10//!
11//! struct UserService {
12//! // your state
13//! }
14//!
15//! #[http]
16//! #[cli(name = "users")]
17//! #[mcp]
18//! #[ws(path = "/ws")]
19//! impl UserService {
20//! /// Create a new user
21//! async fn create_user(&self, name: String, email: String) -> Result<User, UserError> {
22//! // implementation
23//! }
24//!
25//! /// Get user by ID
26//! async fn get_user(&self, id: UserId) -> Option<User> {
27//! // implementation
28//! }
29//!
30//! /// List all users
31//! async fn list_users(&self, limit: Option<u32>) -> Vec<User> {
32//! // implementation
33//! }
34//! }
35//! ```
36//!
37//! This generates:
38//! - **HTTP**: `POST /users`, `GET /users/{id}`, `GET /users` (axum router)
39//! - **CLI**: `users create-user --name X`, `users get-user <id>` (clap)
40//! - **MCP**: Tools `create_user`, `get_user`, `list_users` (Model Context Protocol)
41//! - **WebSocket**: JSON-RPC methods over WebSocket (axum)
42//!
43//! # Available Macros
44//!
45//! | Macro | Protocol | Generated Methods |
46//! |-------|----------|-------------------|
47//! | `#[http]` | HTTP/REST | `http_router()`, `openapi_spec()` |
48//! | `#[cli]` | Command Line | `cli_command()`, `cli_run()` |
49//! | `#[mcp]` | MCP | `mcp_tools()`, `mcp_call()`, `mcp_call_async()` |
50//! | `#[ws]` | WebSocket | `ws_router()`, `ws_handle_message()`, `ws_handle_message_async()` |
51//!
52//! # Naming Conventions
53//!
54//! Method names infer HTTP methods and CLI subcommand structure:
55//!
56//! | Prefix | HTTP | CLI |
57//! |--------|------|-----|
58//! | `create_*`, `add_*` | POST | `<cmd> create-*` |
59//! | `get_*`, `fetch_*` | GET (single) | `<cmd> get-*` |
60//! | `list_*`, `find_*` | GET (collection) | `<cmd> list-*` |
61//! | `update_*`, `set_*` | PUT | `<cmd> update-*` |
62//! | `delete_*`, `remove_*` | DELETE | `<cmd> delete-*` |
63//!
64//! # Return Types
65//!
66//! | Type | HTTP | CLI | MCP/WS |
67//! |------|------|-----|--------|
68//! | `T` | 200 + JSON | stdout JSON | JSON result |
69//! | `Option<T>` | 200 or 404 | stdout or exit 1 | result or null |
70//! | `Result<T, E>` | 200 or error | stdout or stderr | result or error |
71//! | `()` | 204 | silent | `{"success": true}` |
72//! | `impl Stream<Item=T>` | SSE | N/A | N/A |
73//!
74//! # Async Methods
75//!
76//! All macros support async methods:
77//!
78//! ```ignore
79//! #[mcp]
80//! impl MyService {
81//! // Sync method - works with mcp_call() and mcp_call_async()
82//! pub fn sync_method(&self) -> String { ... }
83//!
84//! // Async method - use mcp_call_async() for proper await
85//! pub async fn async_method(&self) -> String { ... }
86//! }
87//!
88//! // Sync call (errors on async methods)
89//! service.mcp_call("sync_method", json!({}));
90//!
91//! // Async call (awaits async methods properly)
92//! service.mcp_call_async("async_method", json!({})).await;
93//! ```
94//!
95//! # SSE Streaming (HTTP)
96//!
97//! Return `impl Stream<Item=T>` for Server-Sent Events:
98//!
99//! ```ignore
100//! #[http]
101//! impl StreamService {
102//! // Note: Rust 2024 requires `+ use<>` to avoid lifetime capture
103//! pub fn stream_events(&self) -> impl Stream<Item = Event> + use<> {
104//! futures::stream::iter(vec![Event { ... }])
105//! }
106//! }
107//! ```
108//!
109//! # Feature Flags
110//!
111//! Enable only what you need:
112//!
113//! ```toml
114//! [dependencies]
115//! server-less = { version = "0.1", default-features = false, features = ["http", "cli"] }
116//! ```
117//!
118//! Available features:
119//! - `mcp` - MCP macro (no extra deps)
120//! - `http` - HTTP macro (requires axum)
121//! - `cli` - CLI macro (requires clap)
122//! - `ws` - WebSocket macro (requires axum, futures)
123//! - `full` - All features (default)
124
125// Re-export macros (feature-gated)
126#[cfg(feature = "mcp")]
127pub use server_less_macros::mcp;
128
129#[cfg(feature = "http")]
130pub use server_less_macros::http;
131
132#[cfg(any(feature = "http", feature = "openapi"))]
133pub use server_less_macros::openapi;
134
135#[cfg(feature = "http")]
136pub use server_less_macros::route;
137
138#[cfg(feature = "http")]
139pub use server_less_macros::response;
140
141#[cfg(feature = "http")]
142pub use server_less_macros::serve;
143
144#[cfg(feature = "cli")]
145pub use server_less_macros::cli;
146
147#[cfg(feature = "cli")]
148pub use server_less_core::CliSubcommand;
149
150#[cfg(feature = "cli")]
151pub use server_less_core::cli_format_output;
152
153#[cfg(feature = "mcp")]
154pub use server_less_core::McpNamespace;
155
156#[cfg(feature = "jsonrpc")]
157pub use server_less_core::JsonRpcMount;
158
159#[cfg(feature = "ws")]
160pub use server_less_core::WsMount;
161
162#[cfg(feature = "http")]
163pub use server_less_core::HttpMount;
164
165#[cfg(feature = "ws")]
166pub use server_less_macros::ws;
167
168#[cfg(feature = "jsonrpc")]
169pub use server_less_macros::jsonrpc;
170
171#[cfg(feature = "openrpc")]
172pub use server_less_macros::openrpc;
173
174#[cfg(feature = "graphql")]
175pub use server_less_macros::graphql;
176#[cfg(feature = "graphql")]
177pub use server_less_macros::graphql_enum;
178#[cfg(feature = "graphql")]
179pub use server_less_macros::graphql_input;
180
181#[cfg(feature = "grpc")]
182pub use server_less_macros::grpc;
183
184#[cfg(feature = "capnp")]
185pub use server_less_macros::capnp;
186
187#[cfg(feature = "thrift")]
188pub use server_less_macros::thrift;
189
190#[cfg(feature = "connect")]
191pub use server_less_macros::connect;
192
193#[cfg(feature = "smithy")]
194pub use server_less_macros::smithy;
195
196#[cfg(feature = "markdown")]
197pub use server_less_macros::markdown;
198
199#[cfg(feature = "jsonschema")]
200pub use server_less_macros::jsonschema;
201
202#[cfg(feature = "asyncapi")]
203pub use server_less_macros::asyncapi;
204
205// Blessed presets
206#[cfg(feature = "http")]
207pub use server_less_macros::server;
208
209#[cfg(feature = "jsonrpc")]
210pub use server_less_macros::rpc;
211
212#[cfg(feature = "mcp")]
213pub use server_less_macros::tool;
214
215#[cfg(feature = "cli")]
216pub use server_less_macros::program;
217
218// Error derive macro (always available - no deps, commonly needed)
219pub use server_less_macros::ServerlessError;
220
221// Re-export futures for generated WebSocket code
222#[cfg(feature = "ws")]
223pub use futures;
224
225// Re-export async-graphql for generated GraphQL code
226#[cfg(feature = "graphql")]
227pub use async_graphql;
228#[cfg(feature = "graphql")]
229pub use async_graphql_axum;
230
231// Re-export core types
232pub use server_less_core::*;
233
234// Re-export OpenAPI composition utilities (available when any protocol that generates OpenAPI is enabled)
235#[cfg(feature = "server-less-openapi")]
236pub use server_less_openapi::{
237 OpenApiBuilder, OpenApiError, OpenApiOperation, OpenApiParameter, OpenApiPath, OpenApiSchema,
238};
239
240// Re-export serde for generated code
241pub use serde;
242pub use serde_json;
243
244/// Prelude for convenient imports
245pub mod prelude {
246 // Runtime protocols
247 #[cfg(feature = "cli")]
248 pub use super::CliSubcommand;
249 #[cfg(feature = "http")]
250 pub use super::HttpMount;
251 #[cfg(feature = "jsonrpc")]
252 pub use super::JsonRpcMount;
253 #[cfg(feature = "mcp")]
254 pub use super::McpNamespace;
255 #[cfg(feature = "ws")]
256 pub use super::WsMount;
257 #[cfg(feature = "cli")]
258 pub use super::cli;
259 #[cfg(feature = "graphql")]
260 pub use super::graphql;
261 #[cfg(feature = "graphql")]
262 pub use super::graphql_enum;
263 #[cfg(feature = "graphql")]
264 pub use super::graphql_input;
265 #[cfg(feature = "http")]
266 pub use super::http;
267 #[cfg(feature = "jsonrpc")]
268 pub use super::jsonrpc;
269 #[cfg(feature = "mcp")]
270 pub use super::mcp;
271 #[cfg(any(feature = "http", feature = "openapi"))]
272 pub use super::openapi;
273 #[cfg(feature = "http")]
274 pub use super::response;
275 #[cfg(feature = "http")]
276 pub use super::route;
277 #[cfg(feature = "http")]
278 pub use super::serve;
279 #[cfg(feature = "ws")]
280 pub use super::ws;
281
282 // Schema generators
283 #[cfg(feature = "capnp")]
284 pub use super::capnp;
285 #[cfg(feature = "connect")]
286 pub use super::connect;
287 #[cfg(feature = "grpc")]
288 pub use super::grpc;
289 #[cfg(feature = "smithy")]
290 pub use super::smithy;
291 #[cfg(feature = "thrift")]
292 pub use super::thrift;
293
294 // Specification generators
295 #[cfg(feature = "asyncapi")]
296 pub use super::asyncapi;
297 #[cfg(feature = "jsonschema")]
298 pub use super::jsonschema;
299 #[cfg(feature = "openrpc")]
300 pub use super::openrpc;
301
302 // Documentation generators
303 #[cfg(feature = "markdown")]
304 pub use super::markdown;
305
306 // Blessed presets
307 #[cfg(feature = "cli")]
308 pub use super::program;
309 #[cfg(feature = "jsonrpc")]
310 pub use super::rpc;
311 #[cfg(feature = "http")]
312 pub use super::server;
313 #[cfg(feature = "mcp")]
314 pub use super::tool;
315
316 // Always available
317 pub use super::{Context, ErrorCode, ErrorResponse, IntoErrorCode, ServerlessError};
318
319 // OpenAPI composition (available when any protocol that generates OpenAPI is enabled)
320 #[cfg(feature = "server-less-openapi")]
321 pub use super::OpenApiBuilder;
322 pub use serde::{Deserialize, Serialize};
323
324 // WebSocket sender (when ws feature enabled)
325 #[cfg(feature = "ws")]
326 pub use super::WsSender;
327}