rod-js
v0.2.1
Published
JavaScript/TypeScript bindings for the Rod validation library
Readme
Rod is a high-performance schema validation engine powered by Rust. It compiles to native binaries, WebAssembly (Node.js/Browser), and Python extensions, allowing you to enforce the exact same validation logic across your entire stack.
Stop rewriting regexes in three different languages. Define it once in Rod, run it everywhere.
🚀 Key Features
- Unified Logic: A
uuid()check in the browser uses the exact same byte-level logic as your Rust backend. No more "Schema Drift." - Zero-Copy Architecture: Rod validates data directly in the host language's memory (V8 Heap, Python Objects, or Rust Structs) without expensive intermediate serialization.
- Fluent API: A chainable builder pattern (
rod.string().min(5)) familiar to Zod/Pydantic users. - Batch Optimization: Specialized bitmask APIs for validating massive datasets (100k+ items) with minimal FFI overhead.
📦 Installation
Rust
cargo add rod-rsJavaScript / TypeScript
npm install rod-jsPython
pip install rod-py⚡ Quick Start
1. Rust
Uses the rod_obj! macro for cleaner syntax.
use rod_rs::{rod_obj, string, number, RodValidator};
use serde_json::json;
fn main() {
// Define schema using the macro
let user_schema = rod_obj! {
name: string().min(3),
email: string().email(),
age: number().int().min(18.0)
};
// Data (e.g., from an API request)
let data = json!({
"name": "Rod",
"email": "[email protected]",
"age": 25
});
// Zero-copy wrap & validate
let input = rod_rs::io::json::wrap(&data);
match user_schema.validate(&input) {
Ok(_) => println!("✅ Valid!"),
Err(e) => println!("❌ Error: {:?}", e.issues),
}
}2. TypeScript
Requires a one-time WASM initialization.
import { rod } from 'rod-js';
await rod.init(); // Initialize WASM
const User = rod.object({
name: rod.string().min(3),
email: rod.string().email(),
tags: rod.array(rod.string()).min(1)
}).strict();
const data = {
name: "Rod",
email: "[email protected]",
tags: ["wasm", "rust"]
};
// 'lazy' mode reads fields on-demand without full serialization
console.log(User.parse(data, { mode: 'lazy' }));3. Python
Native extension via PyO3.
import rod
User = rod.object({
"name": rod.string().min(3),
"email": rod.string().email(),
"tags": rod.array(rod.string()).min(1)
}).strict()
data = {
"name": "Rod",
"email": "[email protected]",
"tags": ["ffi", "rust"]
}
try:
print(User.parse(data))
except ValueError as e:
print(f"Validation failed: {e}")📊 Performance & Architecture
Rod prioritizes correctness and portability.
The "Bridge Tax"
Rod runs inside a Rust core. When used from JS or Python, there is an overhead to cross the language boundary (Foreign Function Interface).
- Simple Objects: For tiny objects (e.g.,
{ a: 1 }), native libraries like Zod (JS) or Pydantic (Python) are faster because they don't pay the FFI tax. - Complex Logic: For heavy validation (UUIDs, huge arrays, complex regex), Rod often outperforms native JS/Python logic.
- Native Rust: Rod is blazingly fast (~200ns per object), comparable to raw handwritten Rust checks.
Recommendation
- Use Rod when you need strict consistency between Backend/Frontend, or when processing batch data.
- Use Zod/Pydantic if you are writing a single-language app and don't need shared logic.
🛠 Development
This is a monorepo managed by just.
| Command | Description |
| :--- | :--- |
| just build-all | Build Rust core, WASM bindings, and Python extension |
| just test-all | Run integration tests across all three languages |
| just bench-all | Run comparative benchmarks against Zod and Pydantic |
📄 License
MIT © Yash Makan
