Expand description
Server-less - Composable derive macros for Rust
Server-less takes an impl-first approach: write your Rust methods, and derive macros project them into various protocols (HTTP, CLI, MCP, WebSocket).
§Quick Start
use server_less::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct User { name: String, email: String }
#[derive(Debug, ServerlessError)]
enum UserError { NotFound }
struct UserService;
#[mcp]
impl UserService {
/// Create a new user
async fn create_user(&self, name: String, email: String) -> Result<User, UserError> {
Ok(User { name, email })
}
/// List all users
async fn list_users(&self, limit: Option<u32>) -> Vec<User> {
let _ = limit;
vec![]
}
}This generates:
- MCP: Tools
create_user,list_users(Model Context Protocol)
§Available Macros
Blessed presets (batteries-included, use these to get started):
| Macro | Combines | Feature |
|---|---|---|
#[server] | #[http] + #[serve(http)] | http |
#[program] | #[cli] + #[markdown] | cli |
#[tool] | #[mcp] + #[jsonschema] | mcp |
#[rpc] | #[jsonrpc] + #[openrpc] + #[serve(jsonrpc)] | jsonrpc |
À la carte macros (explicit composition):
| Macro | Protocol | Generated Methods |
|---|---|---|
#[http] | HTTP/REST | http_router(), openapi_spec() |
#[cli] | Command Line | cli_command(), cli_run(), cli_run_async() |
#[mcp] | MCP | mcp_tools(), mcp_call(), mcp_call_async() |
#[ws] | WebSocket | ws_router(), ws_handle_message(), ws_handle_message_async() |
#[jsonrpc] | JSON-RPC 2.0 | jsonrpc_router(), jsonrpc_methods() |
#[graphql] | GraphQL | async-graphql integration |
#[grpc] | gRPC | .proto schema generation |
Cross-cutting attributes:
| Macro | Purpose |
|---|---|
#[app(...)] | Attach protocol-neutral metadata (name, description, version, homepage) |
#[derive(Config)] | Generate config loading from env vars, TOML files, and defaults |
#[derive(ServerlessError)] | Derive IntoErrorCode + Display + Error for error enums |
#[route(...)] | Per-method HTTP overrides (method, path, skip, hidden) |
#[response(...)] | Per-method response customization |
#[param(...)] | Per-parameter metadata (name, default, location, env, help) |
§Naming Conventions
Method names infer HTTP methods and CLI subcommand structure:
| Prefix | HTTP | CLI |
|---|---|---|
create_*, add_* | POST | <cmd> create-* |
get_*, fetch_* | GET (single) | <cmd> get-* |
list_*, find_* | GET (collection) | <cmd> list-* |
update_*, set_* | PUT | <cmd> update-* |
delete_*, remove_* | DELETE | <cmd> delete-* |
§Return Types
| Type | HTTP | CLI | MCP/WS |
|---|---|---|---|
T | 200 + JSON | stdout JSON | JSON result |
Option<T> | 200 or 404 | stdout or exit 1 | result or null |
Result<T, E> | 200 or error | stdout or stderr | result or error |
() | 204 | silent | {"success": true} |
impl Stream<Item=T> | SSE | N/A | N/A |
§Async Methods
All macros support async methods:
use server_less::prelude::*;
struct MyService;
#[mcp]
impl MyService {
/// Sync method - works with mcp_call() and mcp_call_async()
pub fn sync_method(&self) -> String {
String::from("hello")
}
/// Async method - use mcp_call_async() for proper await
pub async fn async_method(&self) -> String {
String::from("hello async")
}
}
#[tokio::main]
async fn main() {
let service = MyService;
// Sync call (errors on async methods)
service.mcp_call("sync_method", serde_json::json!({}));
// Async call (awaits async methods properly)
service.mcp_call_async("async_method", serde_json::json!({})).await;
}§SSE Streaming (HTTP)
Return impl Stream<Item=T> for Server-Sent Events:
use server_less::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Clone, Serialize, Deserialize)]
struct Event { message: String }
#[derive(Clone)]
struct StreamService;
#[http]
impl StreamService {
// Note: Rust 2024 requires `+ use<>` to avoid lifetime capture
pub fn stream_events(&self) -> impl futures::Stream<Item = Event> + use<> {
futures::stream::iter(vec![Event { message: String::from("hello") }])
}
}§Application Metadata
#[app] attaches protocol-neutral metadata consumed by all protocol macros on the same impl:
use server_less::prelude::*;
use server_less::{app, __app_meta};
#[derive(Clone)]
struct MyApi;
#[app(name = "myapi", description = "My API", version = "1.0.0")]
#[server]
impl MyApi {
pub fn hello(&self) -> String { String::from("hi") }
}Preset macros also accept metadata inline:
use server_less::prelude::*;
#[derive(Clone)]
struct MyApi;
#[server(name = "myapi", description = "My API")]
impl MyApi {
pub fn hello(&self) -> String { String::from("hi") }
}§Config Management
#[derive(Config)] generates config loading from env vars, TOML files, and defaults:
use server_less::prelude::*;
use server_less::{Config as ConfigTrait, ConfigSource};
#[derive(server_less::Config)]
struct AppConfig {
#[param(default = "localhost")]
host: String,
#[param(default = 8080)]
port: u16,
#[param(env = "DATABASE_URL")]
database_url: String,
}Pass the config type to #[server] to add a config subcommand and wire it into serve:
use server_less::prelude::*;
#[derive(Clone)]
struct MyService;
// #[server(config = AppConfig)]
#[server]
impl MyService {
pub fn hello(&self) -> String { String::from("hi") }
}§Feature Flags
Enable only what you need:
[dependencies]
server-less = { version = "0.4", default-features = false, features = ["http", "cli"] }Available features:
mcp- MCP macro (no extra deps)http- HTTP macro (requires axum)cli- CLI macro (requires clap)ws- WebSocket macro (requires axum, futures)jsonrpc- JSON-RPC 2.0 macrographql- GraphQL macro (requires async-graphql)grpc- gRPC schema generationconfig-#[derive(Config)]for config loading (requires toml)full- All features (default)
Re-exports§
pub use futures;pub use async_graphql;pub use async_graphql_axum;pub use serde;pub use serde_json;
Modules§
- __toml
- A serde-compatible TOML-parsing library
- config
- Config management types for
#[derive(Config)]. - error
- Error handling and protocol-specific error mapping.
- extract
- Context and parameter extraction types.
- prelude
- Prelude for convenient imports
Structs§
- Config
Field Meta - Metadata about a single field in a
Config-implementing struct. - Context
- Protocol-agnostic request context.
- Error
Response - A generic error response that can be serialized and sent over the wire.
- Http
Status Helper - Helper wrapper used by generated HTTP handler code to map error values to HTTP status codes.
- Method
Info - Runtime method metadata with string-based types.
- Open
ApiBuilder - Builder for composing OpenAPI specs from multiple sources.
- Open
ApiOperation - An OpenAPI operation (endpoint).
- Open
ApiParameter - An OpenAPI parameter.
- Open
ApiPath - An OpenAPI path with its operations.
- Open
ApiSchema - An OpenAPI schema definition.
- Param
Info - Runtime parameter metadata with string-based types.
- Schema
Validation Error - Error type for schema validation failures.
- Schema
Value Parser - A clap [
TypedValueParser] that usesschemars::JsonSchemato surface enum variants as possible values, andstd::str::FromStrfor actual parsing. - WsSender
- WebSocket sender for server-push messaging.
Enums§
- Config
Error - Error returned by
Config::load. - Config
Source - Specifies where configuration values should be loaded from.
- Error
Code - Protocol-agnostic error code that maps to HTTP status, gRPC code, CLI exit code, etc.
- Http
Method - HTTP method inferred from function name
- Open
ApiError - Errors that can occur during OpenAPI composition.
Traits§
- CliSubcommand
- Trait for types that can be mounted as CLI subcommand groups.
- Config
Trait - Trait implemented by
#[derive(Config)]structs. - Http
Mount - Trait for types that can be mounted as HTTP route groups.
- Http
Status Fallback - Fallback trait used by
HttpStatusHelperwhen the concrete error type does not implementIntoErrorCode. - Into
Error Code - Trait for converting errors to protocol-agnostic error codes.
- Json
RpcMount - Trait for types that can be mounted as JSON-RPC method namespaces.
- McpNamespace
- Trait for types that can be mounted as MCP tool namespaces.
- WsMount
- Trait for types that can be mounted as WebSocket method namespaces.
Functions§
- cli_
format_ output - Format a
serde_json::Valueaccording to the active JSON output flag. - cli_
schema_ for - Generate a JSON Schema for a type at runtime using schemars.
- infer_
path - Infer URL path from method name
Attribute Macros§
- app
- Attach protocol-neutral application metadata to an impl block.
- asyncapi
- Generate AsyncAPI specification for event-driven services.
- capnp
- Generate Cap’n Proto schema from an impl block.
- cli
- Generate a CLI application from an impl block.
- connect
- Generate Connect protocol schema from an impl block.
- graphql
- Generate GraphQL schema from an impl block using async-graphql.
- graphql_
enum - Define a GraphQL enum type.
- graphql_
input - Define a GraphQL input type.
- grpc
- Generate Protocol Buffers schema from an impl block.
- http
- Generate HTTP handlers from an impl block.
- jsonrpc
- Generate JSON-RPC 2.0 handlers over HTTP.
- jsonschema
- Generate JSON Schema from an impl block.
- markdown
- Generate Markdown API documentation from an impl block.
- mcp
- Generate MCP (Model Context Protocol) tools from an impl block.
- openapi
- Generate OpenAPI specification without HTTP routing.
- openrpc
- Generate OpenRPC specification for JSON-RPC services.
- program
- Blessed preset: CLI application with Markdown docs.
- response
- Helper attribute for method-level HTTP response customization.
- route
- Helper attribute for method-level HTTP route customization.
- rpc
- Blessed preset: JSON-RPC server with OpenRPC spec and serve.
- serve
- Coordinate multiple protocol handlers into a single server.
- server
- Blessed preset: HTTP server with OpenAPI and serve.
- smithy
- Generate Smithy IDL schema from an impl block.
- thrift
- Generate Apache Thrift schema from an impl block.
- tool
- Blessed preset: MCP tools with JSON Schema.
- ws
- Generate WebSocket JSON-RPC handlers from an impl block.
Derive Macros§
- Config
- Derive config loading from multiple sources for a struct.
- Serverless
Error - Derive macro for error types that implement
IntoErrorCode.