Getting Started
Install wellformed and validate your first schema in under a minute.
Install
npm install wellformed-tspnpm add wellformed-tsyarn add wellformed-tsbun add wellformed-tscargo add wellformed wellformed-macros serde_jsonNeeds Node 18+ and TypeScript 5+ for the TypeScript package. The Rust crates support Rust 1.93.0+.
Build a schema
import { w } from "wellformed-ts";
const contact = w
.object({
firstName: w.string().trim().minLen(1),
email: w.string().email(),
phone: w.string().phone().optional(),
age: w.integer().min(18).max(120),
})
.strict();use wellformed_macros::wellformed;
const CONTACT: wellformed::EmbeddedSchema = wellformed!("schemas/contact.json");In TypeScript, every method returns this, so you chain. Mark optionals with .optional(). .strict() rejects unknown keys. Rust embeds the serialized schema JSON as a value with wellformed!.
Validate
import { validate } from "wellformed-ts";
const result = validate(contact.toSchema("1.0"), {
firstName: " Alice ",
email: "alice@example.com",
age: 30,
});
result.valid; // true
result.value.firstName; // "Alice", trimmed by the schemause serde_json::json;
use wellformed_macros::wellformed;
const CONTACT: wellformed::EmbeddedSchema = wellformed!("schemas/contact.json");
fn validate_contact() -> wellformed::Result<()> {
let (result, value) = CONTACT.validate_json(r#"{
"firstName": " Alice ",
"email": "alice@example.com",
"age": 30
}"#)?;
assert!(result.is_valid());
assert_eq!(value["firstName"], json!("Alice"));
Ok(())
}On failure, result.errors lists every field with a stable code and message in both runtimes.
Get the type for free
import type { Infer } from "wellformed-ts";
type Contact = Infer<typeof contact>;use wellformed_macros::form_schema;
form_schema!(pub mod contact = "schemas/contact.json");
type Contact = contact::Values;The schema is the source of truth. TypeScript infers from the builder. Rust can use wellformed! for value-style validation, or form_schema! when it needs generated Values, field metadata, and form state helpers.