pub struct ServerMechanism { /* private fields */ }Expand description
Entry point for building an HTTP route.
Pairs an HTTP method with a URL path and acts as the root of a fluent builder chain.
Optionally attach shared state, a JSON body expectation, or URL query parameter
deserialisation — then finalise with onconnect (async) or
onconnect_sync (sync) to produce a SocketType
ready to be mounted on a Server.
§Example
// Plain GET — no body, no state
let health = ServerMechanism::get("/health")
.onconnect(|| async { reply!() });
// POST — JSON body deserialised into `CreateItem`
let create = ServerMechanism::post("/items")
.json::<CreateItem>()
.onconnect(|body| async move {
let item = Item { id: 1, name: body.name };
reply!(json => item, status => Status::Created)
});
// GET — URL query params deserialised into `SearchQuery`
let search = ServerMechanism::get("/search")
.query::<SearchQuery>()
.onconnect(|params| async move {
let _q = params.q;
reply!()
});
// GET — shared counter state injected on every request
let counter: Arc<Mutex<u64>> = Arc::new(Mutex::new(0));
let count_route = ServerMechanism::get("/count")
.state(counter.clone())
.onconnect(|state| async move {
let n = *state.lock().unwrap();
reply!(json => n)
});Implementations§
Source§impl ServerMechanism
impl ServerMechanism
Sourcepub fn get(path: impl Into<String>) -> Self
pub fn get(path: impl Into<String>) -> Self
Creates a route matching HTTP GET requests at path.
Sourcepub fn post(path: impl Into<String>) -> Self
pub fn post(path: impl Into<String>) -> Self
Creates a route matching HTTP POST requests at path.
Sourcepub fn put(path: impl Into<String>) -> Self
pub fn put(path: impl Into<String>) -> Self
Creates a route matching HTTP PUT requests at path.
Sourcepub fn delete(path: impl Into<String>) -> Self
pub fn delete(path: impl Into<String>) -> Self
Creates a route matching HTTP DELETE requests at path.
Sourcepub fn patch(path: impl Into<String>) -> Self
pub fn patch(path: impl Into<String>) -> Self
Creates a route matching HTTP PATCH requests at path.
Sourcepub fn head(path: impl Into<String>) -> Self
pub fn head(path: impl Into<String>) -> Self
Creates a route matching HTTP HEAD requests at path.
Sourcepub fn options(path: impl Into<String>) -> Self
pub fn options(path: impl Into<String>) -> Self
Creates a route matching HTTP OPTIONS requests at path.
Sourcepub fn state<S: Clone + Send + Sync + 'static>(
self,
state: S,
) -> StatefulSocketBuilder<S>
pub fn state<S: Clone + Send + Sync + 'static>( self, state: S, ) -> StatefulSocketBuilder<S>
Attaches shared state S to this route, transitioning to StatefulSocketBuilder.
A fresh clone of S is injected into the handler on every request. For mutable
shared state, wrap the inner value in Arc<Mutex<_>> or Arc<RwLock<_>> before
passing it here — only the outer Arc is cloned per request; the inner data stays
shared across all requests.
S must be Clone + Send + Sync + 'static.
From StatefulSocketBuilder you can further add a JSON body (.json), query
parameters (.query), or encryption (.encryption / .encrypted_query) before
finalising with onconnect.
§Example
use std::sync::{Arc, Mutex};
let db: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));
let route = ServerMechanism::get("/list")
.state(db.clone())
.onconnect(|state| async move {
let items = state.lock().unwrap().clone();
reply!(json => items)
});Sourcepub fn json<T: DeserializeOwned + Send>(self) -> JsonSocketBuilder<T>
pub fn json<T: DeserializeOwned + Send>(self) -> JsonSocketBuilder<T>
Declares that this route expects a JSON-encoded request body, transitioning to
JsonSocketBuilder.
On each incoming request the body is parsed as Content-Type: application/json
and deserialised into T. If the body is absent, malformed, or fails to
deserialise, the request is rejected before the handler is ever called.
When you subsequently call onconnect, the handler
receives a fully-deserialised, ready-to-use T.
T must implement serde::de::DeserializeOwned.
§Example
let route = ServerMechanism::post("/submit")
.json::<Payload>()
.onconnect(|body| async move {
reply!(json => body.value)
});Sourcepub fn query<T: DeserializeOwned + Send>(self) -> QuerySocketBuilder<T>
pub fn query<T: DeserializeOwned + Send>(self) -> QuerySocketBuilder<T>
Declares that this route extracts its input from URL query parameters, transitioning
to QuerySocketBuilder.
On each incoming request the query string (?field=value&...) is deserialised into
T. A missing or malformed query string is rejected before the handler is called.
When you subsequently call onconnect, the handler
receives a fully-deserialised, ready-to-use T.
T must implement serde::de::DeserializeOwned.
§Example
let route = ServerMechanism::get("/items")
.query::<Filter>()
.onconnect(|filter| async move {
let _ = (filter.page, filter.per_page);
reply!()
});Sourcepub fn encryption<T>(self, key: SerializationKey) -> EncryptedBodyBuilder<T>
pub fn encryption<T>(self, key: SerializationKey) -> EncryptedBodyBuilder<T>
Declares that this route expects a VEIL-encrypted request body, transitioning to
EncryptedBodyBuilder.
On each incoming request the raw body bytes are decrypted using the provided
SerializationKey before the handler is called. If the key does not match or
the body is corrupt, the route responds with 403 Forbidden and the handler is
never invoked — meaning the T your handler receives is always a legitimate,
trusted, fully-decrypted value.
Use SerializationKey::Default when both client and server share the built-in key,
or SerializationKey::Value("your-key") for a custom shared secret.
For plain-JSON routes (no encryption) use .json::<T>()
instead.
T must implement bincode::Decode<()>.
§Example
let route = ServerMechanism::post("/submit")
.encryption::<Payload>(SerializationKey::Default)
.onconnect(|body| async move {
// `body` is already decrypted and deserialised — use it directly.
reply!(json => body.value)
});Sourcepub fn encrypted_query<T>(
self,
key: SerializationKey,
) -> EncryptedQueryBuilder<T>
pub fn encrypted_query<T>( self, key: SerializationKey, ) -> EncryptedQueryBuilder<T>
Declares that this route expects VEIL-encrypted URL query parameters, transitioning
to EncryptedQueryBuilder.
The client must send a single ?data=<base64url> query parameter whose value is
the URL-safe base64 encoding of the VEIL-encrypted struct bytes. On each request
the server base64-decodes then decrypts the payload using the provided
SerializationKey. If the data parameter is missing, the encoding is invalid,
the key does not match, or the bytes are corrupt, the route responds with
403 Forbidden and the handler is never invoked — meaning the T your handler
receives is always a legitimate, trusted, fully-decrypted value.
Use SerializationKey::Default or SerializationKey::Value("your-key"). For
plain query-string routes (no encryption) use
.query::<T>() instead.
T must implement bincode::Decode<()>.
Sourcepub fn onconnect<F, Fut, Re>(self, handler: F) -> SocketType
pub fn onconnect<F, Fut, Re>(self, handler: F) -> SocketType
Finalises this route with an async handler that receives no arguments.
Neither a request body nor query parameters are read. The handler runs on every
matching request and must return Result<impl Reply, Rejection>. Use the
[reply!] macro or the standalone reply helpers (reply_with_json,
reply_with_status, etc.) to construct a response.
Returns a SocketType ready to be passed to Server::mechanism.
§Example
let route = ServerMechanism::get("/ping")
.onconnect(|| async {
reply!(json => Pong { ok: true })
});Sourcepub unsafe fn onconnect_sync<F, Re>(self, handler: F) -> SocketType
pub unsafe fn onconnect_sync<F, Re>(self, handler: F) -> SocketType
Finalises this route with a synchronous handler that receives no arguments.
Behaviour and contract are identical to the async variant — neither a body nor query parameters are read — but the closure may block. Each request is dispatched to the blocking thread pool, so the handler must complete quickly to avoid starving other requests.
Returns a SocketType ready to be passed to Server::mechanism.
§Safety
Every incoming request spawns an independent task on Tokio’s blocking thread pool.
The pool caps the number of live OS threads (default 512), but the queue of waiting
tasks is unbounded — under a traffic surge, tasks accumulate without limit, consuming
unbounded memory and causing severe latency spikes or OOM crashes before any queued task
gets a chance to run. Additionally, any panic inside the handler is silently converted
into a Rejection, masking runtime errors. Callers must ensure the handler completes
quickly and that adequate backpressure or rate limiting is applied externally.