Every inbound frame becomes a ServiceRequest. Middleware can inspect or
mutate the byte buffer through frame and frame_mut, adjust correlation
identifiers, or wrap the remainder of the pipeline using Transform. The
Next continuation calls the inner service, returning a ServiceResponse
containing the frame that will be serialized back to the client.[^11]
The middleware::from_fn helper adapts async functions into middleware
components, enabling payload decoding, invocation of the inner service, and
response editing before the response is serialized. HandlerService rebuilds a
packet from the request bytes, invokes the registered handler, and by default
returns the original payload; replies are crafted in middleware (or custom
packet types with interior mutability). Decode typed payloads via the Message
helpers, then write the encoded response into
ServiceResponse::frame_mut().[^10][^12]
use std::convert::Infallible;
use wireframe::{
app::Envelope,
message::Message,
middleware::{from_fn, HandlerService, Next, ServiceRequest, ServiceResponse},
};
#[derive(bincode::Encode, bincode::BorrowDecode)]
struct Ping(u8);
#[derive(bincode::Encode, bincode::BorrowDecode)]
struct Pong(u8);
async fn decode_and_respond(
mut req: ServiceRequest,
next: Next<'_, HandlerService<Envelope>>,
) -> Result<ServiceResponse, Infallible> {
let ping = Ping::from_bytes(req.frame()).map(|(msg, _)| msg).ok();
let mut response = next.call(req).await?;
if let Some(Ping(value)) = ping {
let bytes = Pong(value + 1)
.to_bytes()
.expect("encode Pong");
response.frame_mut().clear();
response.frame_mut().extend_from_slice(&bytes);
}
Ok(response)
}
let middleware = from_fn(decode_and_respond);
Advanced integrations can adopt the wireframe::extractor module, which
defines MessageRequest, Payload, and FromMessageRequest for building
Actix-style extractors in custom middleware or services. These types expose
shared state, peer addresses, and payload cursors for frameworks that want to
layer additional ergonomics on top of the core primitives.[^13]