AnyVali
Native validation libraries for 10 languages, one portable schema model.
Website · Docs · Issues · Contributing
AnyVali lets you write validation schemas in your language, then share them across any of 10 supported runtimes via a portable JSON format. Think Zod, but for every language.
Why AnyVali?
- Write schemas natively -- idiomatic APIs for each language, not a separate DSL
- Share across languages -- export to JSON, import in any other SDK
- Safe numeric defaults --
number= float64,int= int64 everywhere - Deterministic parsing -- coerce, default, then validate, in that order
- Conformance tested -- shared test corpus ensures identical behavior across SDKs
Install
npm install anyvali # JavaScript / TypeScript
pip install anyvali # Python
go get github.com/BetterCorp/AnyVali/sdk/go # Go
cargo add anyvali # Rust
dotnet add package AnyVali # C#
composer require anyvali/anyvali # PHP
gem install anyvali # Ruby
Java / Kotlin / C++
**Java (Maven)** ```xmlQuick Start
Define a schema, parse input, get structured errors or clean data.
| JavaScript / TypeScript | Python |
|---|---|
| ```typescript import { string, int, object, array } from "anyvali"; const User = object({ name: string().minLength(1), email: string().format('email'), age: int().min(0).optional(), tags: array(string()).maxItems(5), }); // Throws on failure const user = User.parse(input); // Or get a result object const result = User.safeParse(input); if (!result.success) { console.log(result.issues); } ``` | ```python import anyvali as v User = v.object_({ "name": v.string().min_length(1), "email": v.string().format("email"), "age": v.int_().min(0).optional(), "tags": v.array(v.string()).max_items(5), }) # Raises on failure user = User.parse(input_data) # Or get a result object result = User.safe_parse(input_data) if not result.success: print(result.issues) ``` |
Go example
```go import av "github.com/BetterCorp/AnyVali/sdk/go" User := av.Object(map[string]av.Schema{ "name": av.String().MinLength(1), "email": av.String().Format("email"), "age": av.Optional(av.Int().Min(0)), "tags": av.Array(av.String()).MaxItems(5), }) result := User.SafeParse(input) if !result.Success { for _, issue := range result.Issues { fmt.Printf("[%s] %s at %v\n", issue.Code, issue.Message, issue.Path) } } ```Type Inference
All 10 SDKs now provide static type inference, so parsed values carry the correct type without manual casts. The TypeScript SDK offers full Zod-style Infer<T>:
import { object, string, int, type Infer } from "anyvali";
const User = object({
name: string().minLength(1),
email: string().format('email'),
age: int().min(0).optional(),
});
type User = Infer<typeof User>;
// => { name: string; email: string; age?: number | undefined }
const user = User.parse(input); // fully typed, no cast needed
Other SDKs use the type inference mechanism native to each language:
- Python --
BaseSchema(Generic[T]),ParseResult(Generic[T]);parse()returnsT - C# / Kotlin --
Schema<T>generic base class,ParseResult<T> - Java --
Schema<T>generic base,ParseResult<T>record - Go --
TypedParse[T]()andTypedSafeParse[T]()generic helper functions - Rust --
TypedSchematrait with associatedOutputtype,parse_as<T>()free function - C++ -- Template
parse_as<T>()andsafe_parse_as<T>()helpers - PHP --
@templatephpDoc annotations for PHPStan/Psalm - Ruby -- RBS type signature file for Steep/Sorbet
Cross-Language Schema Sharing
AnyVali's core feature: export a schema from one language, import it in another.
// TypeScript frontend -- export
const doc = User.export();
const json = JSON.stringify(doc);
// Send to your backend, save to DB, put in a config file...
# Python backend -- import
import json, anyvali as v
schema = v.import_schema(json.loads(schema_json))
result = schema.safe_parse(request_body) # Same validation rules!
Forms
The JS SDK also ships a small forms layer for browser-native fields, HTML5 attributes, and AnyVali validation.
import { object, string, int } from "anyvali";
import { initForm } from "anyvali/forms";
const Signup = object({
email: string().format("email"),
age: int().min(18),
});
initForm("#signup", { schema: Signup });
<form id="signup">
<input name="email" type="email" />
<input name="age" type="number" />
<button type="submit">Create account</button>
</form>
For JSX-style attribute binding:
import { object, string } from "anyvali";
import { createFormBindings } from "anyvali/forms";
const Signup = object({
email: string().format("email"),
});
const form = createFormBindings({ schema: Signup });
<input {...form.field("email")} />;
The portable JSON format:
{
"anyvaliVersion": "1.0",
"schemaVersion": "1",
"root": {
"kind": "object",
"properties": {
"name": { "kind": "string", "minLength": 1 },
"email": { "kind": "string", "format": "email" }
},
"required": ["name", "email"],
"unknownKeys": "strip"
},
"definitions": {},
"extensions": {}
}
Supported SDKs
| Language | Package | Status |
|---|---|---|
| JavaScript / TypeScript | anyvali |
v0.0.1 |
| Python | anyvali |
v0.0.1 |
| Go | github.com/BetterCorp/AnyVali/sdk/go |
v0.0.1 |
| Java | com.anyvali:anyvali |
v0.0.1 |
| C# | AnyVali |
v0.0.1 |
| Rust | anyvali |
v0.0.1 |
| PHP | anyvali/anyvali |
v0.0.1 |
| Ruby | anyvali |
v0.0.1 |
| Kotlin | com.anyvali:anyvali |
v0.0.1 |
| C++ | anyvali (CMake) |
v0.0.1 |
CLI & HTTP API
Don't need an SDK? Use AnyVali from the command line or as a validation microservice.
# Validate from the command line
anyvali validate schema.json '{"name": "Alice", "email": "alice@test.com"}'
# Pipe from stdin
cat payload.json | anyvali validate schema.json -
# Start a validation server
anyvali serve --port 8080 --schemas ./schemas/
# Validate via HTTP
curl -X POST http://localhost:8080/validate/user \
-H "Content-Type: application/json" \
-d '{"name": "Alice", "email": "alice@test.com"}'
Pre-built binaries for Linux, macOS, and Windows are available on the releases page. Docker image: docker pull anyvali/cli.
See the CLI Reference and HTTP API Reference for full documentation.
Schema Types
| Category | Types |
|---|---|
| Primitives | string, bool, null |
| Numbers | number (float64), int (int64), float32, float64, int8-int64, uint8-uint64 |
| Special | any, unknown, never |
| Values | literal, enum |
| Collections | array, tuple, object, record |
| Composition | union, intersection |
| Modifiers | optional, nullable |
Documentation
| Guide | Description |
|---|---|
| Getting Started | Installation, API reference, examples |
| Numeric Semantics | Why number = float64 and int = int64 |
| Portability Guide | Design schemas that work across all languages |
| SDK Authors Guide | Implement a new AnyVali SDK |
| Canonical Spec | The normative specification |
| JSON Format | Interchange format details |
| CLI Reference | Command-line validation tool |
| HTTP API | Validation microservice / sidecar |
| Development | Building, testing, contributing |
Repository Layout
.
├── docs/ Documentation guides
├── spec/ Canonical spec, JSON format, conformance corpus
├── sdk/
│ ├── js/ JavaScript / TypeScript SDK
│ ├── python/ Python SDK
│ ├── go/ Go SDK
│ ├── java/ Java SDK
│ ├── csharp/ C# SDK
│ ├── rust/ Rust SDK
│ ├── php/ PHP SDK
│ ├── ruby/ Ruby SDK
│ ├── kotlin/ Kotlin SDK
│ └── cpp/ C++ SDK
├── cli/ CLI binary and HTTP API server (Go)
├── runner.sh Build/test/CI runner
└── site/ anyvali.com source
Contributing
Contributions are welcome. Please read CONTRIBUTING.md before opening a pull request.
./runner.sh help # See all commands
./runner.sh test js # Test a specific SDK
./runner.sh ci # Run the full CI pipeline locally
pwsh -File tools/release/build_release.ps1 # Build release artifacts with Docker
License
AnyVali is licensed under the MIT License.