vld-dioxus 0.3.0

Dioxus integration for the vld validation library — shared validation for server functions and WASM clients
Documentation

vld-dioxus

Dioxus integration for the vld validation library.

Define validation rules once — use them on both server and client (WASM).

No direct dependency on dioxus — works with any Dioxus version (0.5, 0.6, 0.7+) and compiles for WASM targets.

Installation

[dependencies]
vld = "0.1"
vld-dioxus = "0.1"
dioxus = "0.7"  # or your version

Quick Start

1. Shared Validation Schemas

Define schema factories in a shared module compiled for both server and WASM:

// shared.rs
pub fn name_schema() -> vld::primitives::ZString {
    vld::string().min(2).max(50)
}

pub fn email_schema() -> vld::primitives::ZString {
    vld::string().email()
}

pub fn age_schema() -> vld::primitives::ZInt {
    vld::number().int().min(0).max(150)
}

2. Server Function Validation

Use validate_args! inside #[server] functions:

use dioxus::prelude::*;

#[server]
async fn create_user(
    name: String,
    email: String,
    age: i64,
) -> Result<(), ServerFnError> {
    vld_dioxus::validate_args! {
        name  => shared::name_schema(),
        email => shared::email_schema(),
        age   => shared::age_schema(),
    }
    .map_err(|e| ServerFnError::new(e.to_string()))?;

    // ... insert into database
    Ok(())
}

3. Client-Side Reactive Validation

Use check_field inside Dioxus use_memo hooks for instant feedback:

#[component]
fn CreateUserForm() -> Element {
    let mut name = use_signal(String::new);
    let mut email = use_signal(String::new);

    let name_err = use_memo(move || {
        let v = name();
        if v.is_empty() { return None; }
        vld_dioxus::check_field(&v, &shared::name_schema())
    });

    let email_err = use_memo(move || {
        let v = email();
        if v.is_empty() { return None; }
        vld_dioxus::check_field(&v, &shared::email_schema())
    });

    rsx! {
        form {
            input {
                r#type: "text",
                placeholder: "Name",
                oninput: move |evt| name.set(evt.value()),
            }
            if let Some(err) = name_err() {
                span { class: "error", "{err}" }
            }

            input {
                r#type: "email",
                placeholder: "Email",
                oninput: move |evt| email.set(evt.value()),
            }
            if let Some(err) = email_err() {
                span { class: "error", "{err}" }
            }

            button { r#type: "submit", "Create" }
        }
    }
}

4. Server -> Client Error Display

Parse structured errors from server function responses:

#[component]
fn CreateUserForm() -> Element {
    let create = use_server_future(move || create_user(name(), email(), age()));

    let server_errors = use_memo(move || {
        create.value()
            .and_then(|r| r.as_ref().err())
            .and_then(|e| vld_dioxus::VldServerError::from_json(&e.to_string()))
    });

    rsx! {
        form {
            input { r#type: "text", name: "name" }
            if let Some(ref errs) = server_errors() {
                if errs.has_field_error("name") {
                    span { class: "error",
                        "{errs.field_error(\"name\").unwrap_or_default()}"
                    }
                }
            }
            // ...
        }
    }
}

API Reference

Error Types

Type Description
VldServerError Structured error with per-field messages, serializable for transport
FieldError Single field error: { field, message }

VldServerError Methods

Method Returns Description
validation(fields) VldServerError Create from a list of FieldError
internal(msg) VldServerError Create an internal error
field_error(name) Option<&str> First error message for a field
field_errors(name) Vec<&str> All error messages for a field
has_field_error(name) bool Check if a field has errors
error_fields() Vec<&str> All field names with errors
from_json(s) Option<Self> Parse from JSON string
to_string() String Serialize to JSON (via Display)

Validation Functions

Function Use Case
validate::<Schema, T>(data) Validate a Serialize struct against a vld::schema! type
validate_value::<Schema>(json) Validate a serde_json::Value directly
check_field(value, schema) Single-field check -> Option<String> error
check_field_all(value, schema) Single-field check -> Vec<String> all errors
check_all_fields::<Schema, T>(data) Multi-field check -> Vec<FieldError>

Macros

Macro Description
validate_args! { field => schema, ... } Inline validation of server function arguments

Custom Error Type

For advanced use cases, wrap VldServerError in your own error enum:

use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AppError {
    Validation(vld_dioxus::VldServerError),
    NotFound(String),
    Internal(String),
}

// Implement FromServerFnError for AppError...

#[server]
async fn create_user(name: String) -> Result<(), AppError> {
    vld_dioxus::validate_args! {
        name => vld::string().min(2),
    }
    .map_err(AppError::Validation)?;
    Ok(())
}

Running the Example

cargo run -p vld-dioxus --example dioxus_basic

License

MIT