Shape: An object shape validation utility.#
A schema validator in the tradition of Joi or JSON-Schema, but with a much nicer developer experience. It runs in JavaScript and TypeScript—in the browser and on the backend—in Go and in Rust.
The big idea: your schema looks (almost) exactly like your data.
const { Shape } = require('shape')
const shape = Shape({
port: 8080, // optional, defaults to 8080, must be a number
host: 'localhost', // optional, defaults to 'localhost', must be a string
debug: Boolean, // required, must be a boolean
})
shape({ debug: true })
// → { debug: true, port: 8080, host: 'localhost' }
The same schema in Go:
import "github.com/rjrodger/shape/go"
s := shape.MustShape(map[string]any{
"port": 8080,
"host": "localhost",
"debug": shape.Boolean,
})
out, _ := s.Validate(map[string]any{"debug": true})
// out == map[string]any{"port": 8080, "host": "localhost", "debug": true}
And in Rust:
use shape::{shape, Schema, Value};
let s = Schema::new(shape!({
"port": 8080,
"host": "localhost",
"debug": Boolean,
}));
let out = s.validate(Value::from(serde_json::json!({ "debug": true })))?;
// out == { "debug": true, "port": 8080, "host": "localhost" }
Literal values are optional with a default; type markers (String,
Number, Boolean, …) are required. Objects and arrays fill out and
validate to any depth.
Install#
npm install shape # JavaScript / TypeScript
go get github.com/rjrodger/shape/go # Go (1.22+)
cargo add shape-schema # Rust (1.75+)
Documentation#
Full documentation, organized with the Diátaxis system,
lives in docs/ and is published at
rjrodger.github.io/shape, along with
a performance report comparing
shape to other validators across hosts and versions:
- Getting started—build your first shape, step by step (TS and Go; Rust in its how-to).
- How-to guides—validate options, require fields, objects, arrays & tuples, custom validation, composition, coercion & formats, errors, JSON Schema export and import, and more.
- Reference—builders, Shape API, errors, nodes, TypeScript types, Go API, Rust API.
- Explanation—schema by example, how validation works, TS ↔ Go ↔ Rust parity.
Highlights#
- Optional-by-default: a literal is its own default and type.
- Required fields via type markers.
- Deep object/array filling and validation.
- A rich, composable builder set (
Min,Max,One,Exact,Check,Rename,Refer, …). - Coercion (
Coerce), string formats (Email,Url,Uuid,DateTime,Ip),IntegerandDatekinds,Nullable. - Discriminated unions, and an object algebra (
Pick,Omit,Partial,Extend) to build one shape out of another. Catcha failure with a fallback,Transforma valid value,Describea node for tooling.- JSON Schema export and import (draft 2020-12) and Standard Schema V1 interop.
- A compact string DSL (
expr/build) and inline key expressions. - Detailed, path-aware error messages.
- TypeScript, Go and Rust implementations kept at behavioural parity by a shared conformance corpus and a differential harness.
- Full TypeScript inference of the produced type through every builder, and Go structs accepted as values and as specs.
- Benchmarks against Zod, Ajv, Joi and Valibot (TypeScript), validator, jsonschema and gojsonschema (Go), and garde, validator and jsonschema (Rust), recorded from several hosts on the performance report.
Repository layout#
| Path | Contents |
|---|---|
ts/ |
Canonical TypeScript implementation and tests. See ts/README.md. |
go/ |
Go port and tests. See go/README.md. |
rs/ |
Rust port and tests. See rs/README.md. |
docs/ |
Diátaxis documentation. |
test/ |
Shared, language-neutral conformance corpus. |
bench/ |
Benchmarks against other validators and the recorded runs. See bench/README.md. |
site/ |
Builds the project site: the docs and the performance report. |
AGENTS.md |
Contributor & AI-agent guide (build, test, parity rules). |
Contributing#
make build builds all three languages; make test runs all three test suites
(including the shared corpus); make diff runs the differential parity
harness, which puts thousands of generated cases through all three and
compares exact error text.
TypeScript is canonical—behaviour changes start there and are mirrored in Go
and Rust.
See AGENTS.md.
Credits#
This module is inspired by Joi, which Richard Rodger used for many years. It also draws from the way Vue does property validation.
SHAPE#
The name comes from a sort of in-joke in Irish politics. It is grotesque, unbelievable, bizarre and unprecedented that anyone would write yet another validation library for JavaScript, let alone a third one. (See parambulator and norma—but don't use those; Shape is the one that is maintained.) Short names help, too.
License#
Copyright (c) 2021-2024 Richard Rodger and other contributors. Licensed under MIT.