Module extractor

Module extractor 

Source
Expand description

Type-safe data extraction from WebSocket messages and context.

This module provides a powerful type extraction system inspired by frameworks like Axum, allowing handlers to declaratively specify what data they need. Extractors automatically parse and validate data from messages, connection state, and application context.

§Overview

Extractors are types that implement the FromMessage trait. They can extract:

  • Message content: JSON, binary data, text
  • Connection info: Client address, connection ID, metadata
  • Application state: Shared data like database pools, configuration
  • Route parameters: Path and query parameters from routing
  • Custom extensions: User-defined request-scoped data

§Design Philosophy

The extractor system follows these principles:

  • Type safety: Extraction failures are caught at runtime with clear errors
  • Composability: Multiple extractors can be used in a single handler
  • Zero cost: Extraction happens only once per handler invocation
  • Flexibility: Custom extractors can be easily implemented

§Built-in Extractors

ExtractorDescriptionExample
Json<T>Deserialize JSON from messageJson(user): Json<User>
State<T>Extract shared application stateState(db): State<Arc<Database>>
ConnectionGet the active connectionconn: Connection
ConnectInfoGet connection metadataConnectInfo(info)
MessageGet raw messagemsg: Message
DataExtract binary dataData(bytes)
Path<T>Extract path parametersPath(id): Path<UserId>
Query<T>Extract query parametersQuery(params): Query<SearchParams>
Extension<T>Extract custom extensionsExtension(auth): Extension<Auth>

§Examples

§Simple JSON Extraction

use wsforge::prelude::*;
use serde::Deserialize;

#[derive(Deserialize)]
struct ChatMessage {
    username: String,
    text: String,
}

async fn chat_handler(Json(msg): Json<ChatMessage>) -> Result<String> {
    println!("{} says: {}", msg.username, msg.text);
    Ok(format!("Message from {} received", msg.username))
}

§Multiple Extractors

use wsforge::prelude::*;
use serde::Deserialize;
use std::sync::Arc;

#[derive(Deserialize)]
struct GameMove {
    player: String,
    action: String,
}

async fn game_handler(
    Json(game_move): Json<GameMove>,
    conn: Connection,
    State(manager): State<Arc<ConnectionManager>>,
) -> Result<()> {
    println!("Player {} from connection {} made move: {}",
        game_move.player, conn.id(), game_move.action);

    // Broadcast to other players
    manager.broadcast_except(conn.id(),
        Message::text(format!("{} moved", game_move.player)));

    Ok(())
}

§Custom Extractors

use wsforge::prelude::*;
use async_trait::async_trait;

// Custom extractor for authenticated users
struct AuthUser {
    user_id: u64,
    username: String,
}

#[async_trait]
impl FromMessage for AuthUser {
    async fn from_message(
        message: &Message,
        conn: &Connection,
        state: &AppState,
        extensions: &Extensions,
    ) -> Result<Self> {
        // Extract authentication token from message
        let text = message.as_text()
            .ok_or_else(|| Error::extractor("Message must be text"))?;

        // Validate and extract user info
        // (In production, verify JWT, session token, etc.)
        Ok(AuthUser {
            user_id: 123,
            username: "user".to_string(),
        })
    }
}

async fn protected_handler(user: AuthUser) -> Result<String> {
    Ok(format!("Hello, {}!", user.username))
}

Structs§

ConnectInfo
Extractor for connection metadata.
Data
Extractor for raw binary data.
Extension
Extractor for custom extension data.
Extensions
Container for request-scoped extension data.
Json
Extractor for JSON data from messages.
Path
Extractor for path parameters.
Query
Extractor for query parameters.
State
Extractor for shared application state.

Traits§

FromMessage
Trait for types that can be extracted from WebSocket messages and context.