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 = "ws")]
148pub use server_less_macros::ws;
149
150#[cfg(feature = "jsonrpc")]
151pub use server_less_macros::jsonrpc;
152
153#[cfg(feature = "openrpc")]
154pub use server_less_macros::openrpc;
155
156#[cfg(feature = "graphql")]
157pub use server_less_macros::graphql;
158#[cfg(feature = "graphql")]
159pub use server_less_macros::graphql_enum;
160#[cfg(feature = "graphql")]
161pub use server_less_macros::graphql_input;
162
163#[cfg(feature = "grpc")]
164pub use server_less_macros::grpc;
165
166#[cfg(feature = "capnp")]
167pub use server_less_macros::capnp;
168
169#[cfg(feature = "thrift")]
170pub use server_less_macros::thrift;
171
172#[cfg(feature = "connect")]
173pub use server_less_macros::connect;
174
175#[cfg(feature = "smithy")]
176pub use server_less_macros::smithy;
177
178#[cfg(feature = "markdown")]
179pub use server_less_macros::markdown;
180
181#[cfg(feature = "jsonschema")]
182pub use server_less_macros::jsonschema;
183
184#[cfg(feature = "asyncapi")]
185pub use server_less_macros::asyncapi;
186
187// Error derive macro (always available - no deps, commonly needed)
188pub use server_less_macros::ServerlessError;
189
190// Re-export futures for generated WebSocket code
191#[cfg(feature = "ws")]
192pub use futures;
193
194// Re-export async-graphql for generated GraphQL code
195#[cfg(feature = "graphql")]
196pub use async_graphql;
197#[cfg(feature = "graphql")]
198pub use async_graphql_axum;
199
200// Re-export core types
201pub use server_less_core::*;
202
203// Re-export OpenAPI composition utilities
204pub use server_less_openapi::{
205 OpenApiBuilder, OpenApiError, OpenApiOperation, OpenApiParameter, OpenApiPath, OpenApiSchema,
206};
207
208// Re-export serde for generated code
209pub use serde;
210pub use serde_json;
211
212/// Prelude for convenient imports
213pub mod prelude {
214 // Runtime protocols
215 #[cfg(feature = "cli")]
216 pub use super::cli;
217 #[cfg(feature = "graphql")]
218 pub use super::graphql;
219 #[cfg(feature = "graphql")]
220 pub use super::graphql_enum;
221 #[cfg(feature = "graphql")]
222 pub use super::graphql_input;
223 #[cfg(feature = "http")]
224 pub use super::http;
225 #[cfg(feature = "jsonrpc")]
226 pub use super::jsonrpc;
227 #[cfg(feature = "mcp")]
228 pub use super::mcp;
229 #[cfg(any(feature = "http", feature = "openapi"))]
230 pub use super::openapi;
231 #[cfg(feature = "http")]
232 pub use super::response;
233 #[cfg(feature = "http")]
234 pub use super::route;
235 #[cfg(feature = "http")]
236 pub use super::serve;
237 #[cfg(feature = "ws")]
238 pub use super::ws;
239
240 // Schema generators
241 #[cfg(feature = "capnp")]
242 pub use super::capnp;
243 #[cfg(feature = "connect")]
244 pub use super::connect;
245 #[cfg(feature = "grpc")]
246 pub use super::grpc;
247 #[cfg(feature = "smithy")]
248 pub use super::smithy;
249 #[cfg(feature = "thrift")]
250 pub use super::thrift;
251
252 // Specification generators
253 #[cfg(feature = "asyncapi")]
254 pub use super::asyncapi;
255 #[cfg(feature = "jsonschema")]
256 pub use super::jsonschema;
257 #[cfg(feature = "openrpc")]
258 pub use super::openrpc;
259
260 // Documentation generators
261 #[cfg(feature = "markdown")]
262 pub use super::markdown;
263
264 // Always available
265 pub use super::{
266 Context, ErrorCode, ErrorResponse, IntoErrorCode, OpenApiBuilder, ServerlessError,
267 };
268 pub use serde::{Deserialize, Serialize};
269
270 // WebSocket sender (when ws feature enabled)
271 #[cfg(feature = "ws")]
272 pub use super::WsSender;
273}