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/js # 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 # RubyJava (Maven)
<dependency>
<groupId>com.anyvali</groupId>
<artifactId>anyvali</artifactId>
<version>0.0.1</version>
</dependency>Kotlin (Gradle)
implementation("com.anyvali:anyvali:0.0.1")C++ (CMake)
FetchContent_Declare(anyvali GIT_REPOSITORY https://github.com/BetterCorp/AnyVali)
FetchContent_MakeAvailable(anyvali)
target_link_libraries(your_target PRIVATE anyvali)Quick Start
Define a schema, parse input, get structured errors or clean data.
| JavaScript / TypeScript | Python |
|---|---|
import { string, int, object, array } from "@anyvali/js";
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);
} |
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) |
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/js";
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 neededOther 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/js";
import { initForm } from "@anyvali/js/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/js";
import { createFormBindings } from "@anyvali/js/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": "reject"
},
"definitions": {},
"extensions": {}
}Supported SDKs
| Language | Package | Status |
|---|---|---|
| JavaScript / TypeScript | @anyvali/js |
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 DockerLicense
AnyVali is licensed under the MIT License.
