Skip to main content

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}