
🚀 Why Data Validation Matters
Data validation is a crucial part of modern web applications, ensuring data integrity, security, and a smooth user experience. However, developers often struggle with:
- Writing separate validation logic for frontend and backend
- Managing multiple validation libraries across environments
- Keeping validation consistent between client and server
Introducing IsoValid—a powerful, isomorphic validation library that allows you to use the same validation logic across both browser and Node.js environments.
🔥 What is IsoValid?
IsoValid is a lightweight, TypeScript-first validation library designed to unify validation across your entire application stack. Whether you're validating user input in a React form or ensuring API request integrity in an Express server, IsoValid makes it seamless.
🌟 Key Features
✅ True Isomorphic Support – The same validation code runs in both frontend and backend ✅ TypeScript-First – Fully typed API for strong type inference ✅ Minimal Bundle Size – No unnecessary dependencies or bloat ✅ Intuitive API – Developer-friendly, chainable syntax ✅ High Performance – Optimized validation with minimal overhead ✅ Extensible – Easily add custom validators and error messages
📦 Installation
Get started with IsoValid in seconds:
npm install isovalid
🔹 Core Architecture
IsoValid is built on a flexible, extensible architecture that includes:
Base Schema Class
- Foundation for all validation schemas
- Handles optional/nullable states
- Common validation logic across types
Type-Specific Schemas
- StringSchema – Length, regex, email, trimming, etc.
- NumberSchema – Min/max, integer, positive/negative checks
- More types coming soon (Boolean, Array, Object)
Validation Pipeline
- Multi-stage validation process
- Supports custom validation functions
- Returns detailed error reporting
⚡ Usage Examples
String Validation
import { v } from 'isovalid';
const stringSchema = v.string() .min(2) // Minimum length .max(50) // Maximum length .email() // Must be a valid email .matches(/regex/) // Custom pattern .trimmed() // Remove extra whitespace .setOptional() // Allow undefined .setNullable(); // Allow null
Number Validation
const numberSchema = v.number() .min(0) // Minimum value .max(100) // Maximum value .integer() // Must be an integer .positive(); // Must be > 0
Validation Results
interface ValidationResult { valid: boolean; errors: Array<{ path: string[]; message: string; }>; }
🎯 Real-World Examples
1. React Form Validation
import { v } from 'isovalid'; import { useState, FormEvent } from 'react';
const userSchema = { username: v.string().min(3).max(20), email: v.string().email(), age: v.number().integer().min(18) };
function RegistrationForm() { const [formData, setFormData] = useState({ username: '', email: '', age: '' }); const [errors, setErrors] = useState<Record<string, string>>({});
const validateField = (field: keyof typeof userSchema, value: any) => { const result = userSchema[field].validate(value); return result.valid ? null : result.errors[0].message; };
const handleSubmit = (e: FormEvent) => { e.preventDefault(); const newErrors: Record<string, string> = {};
Object.entries(formData).forEach(([field, value]) => { const error = validateField(field as keyof typeof userSchema, value); if (error) newErrors[field] = error; });
if (Object.keys(newErrors).length === 0) { console.log('Submitting:', formData); } else { setErrors(newErrors); } };
return ( <form onSubmit={handleSubmit}> <input type="text" placeholder="Username" onChange={e => setFormData(prev => ({ ...prev, username: e.target.value }))} /> {errors.username && <span>{errors.username}</span>} <button type="submit">Register</button> </form> ); }
2. Express API Validation
import express from 'express'; import { v } from 'isovalid';
const app = express(); app.use(express.json());
const productSchema = { name: v.string().min(3).max(100), price: v.number().min(0), category: v.string().custom(value => ['electronics', 'books', 'clothing'].includes(value) ? null : 'Invalid category' ) };
app.post('/api/products', (req, res) => { const errors = Object.entries(productSchema) .map(([field, schema]) => ({ field, result: schema.validate(req.body[field]) })) .filter(({ result }) => !result.valid) .map(({ field, result }) => ({ field, message: result.errors[0].message }));
if (errors.length > 0) { return res.status(400).json({ errors }); }
res.status(201).json(req.body); });
🎯 Best Practices
✅ Schema Reuse – Define schemas once & share across frontend/backend ✅ Type Safety – Leverage TypeScript’s inference capabilities ✅ Performance Optimization – Cache schema instances for reuse ✅ Error Handling – Always check .valid before using data
🛠️ Roadmap
🚀 Upcoming Features:
-
📌 Get Started with IsoValid
IsoValid is open-source and welcomes contributions! Try it today and share your feedback.
🔗 NPM Package: IsoValid on NPM 🔗 GitHub Repository: GitHub Repo
Let’s make data validation simpler together! 🚀
