Skip to content

JSON Type implementation. Fast JSON data type schema validation with JIT compilation.

Notifications You must be signed in to change notification settings

jsonjoy-com/json-type

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

JSON Type

Modern type system for JSON. JSON Type is way a new way to specify JSON schema, it is an alternative and improvement over JSON Schema and JSON Type Definition.

Features of the library:

  • JIT compilation for schema validator.
  • JIT compilation for JSON (text) serializer.
  • JIT compilation for CBOR, MessagePack, and JSON (binary) serializers.
  • JIT compilation for safe serialization size estimation.
  • Schema export and import.
  • Const types.
  • Union type discriminator is specified using the JSON Expression language.
  • Some discriminators are automatically inferred, when const types are used.
  • Custom validation rules can be added using the JSON Expression language.
  • Can generate random JSON values that match the schema.

Quick Start

Define a user schema and validate data in just a few lines:

import {t} from '@jsonjoy.com/json-type'; // Define a user type const User = t.object({ id: t.num, name: t.str, email: t.str, }).optional({ age: t.num.gte(0).lte(120), }); // Validate data const isValid = User.validateSchema(); User.validate({ id: 1, name: "Alice", email: "alice@example.com", age: 30 }); // âś… Valid // Generate random test data const randomUser = User.random(); // { id: 42, name: "xyz123", email: "abc", age: 25 }

Advanced Features

JSON Type goes beyond basic validation with powerful JIT compilation:

// Compile ultra-fast validators const validator = User.compileValidator({errors: 'boolean'}); const isValid = validator(userData); // Blazing fast validation // Generate TypeScript types const tsCode = User.toTypeScript(); // type User = { id: number; name: string; email: string; age?: number; } // Compile optimized serializers const toJson = User.compileEncoder('json'); const jsonString = toJson(userData); // Faster than JSON.stringify const toCbor = User.compileCborEncoder(); const cborBytes = toCbor(userData); // Binary serialization

Real-World Example

Build type-safe APIs with complex schemas:

import {t} from '@jsonjoy.com/json-type'; // Define API request/response types const CreatePostRequest = t.object({ title: t.str.options({min: 1, max: 100}), content: t.str.options({min: 10}), tags: t.array(t.str).options({max: 5}), published: t.bool, }); const Post = t.object({ id: t.str, title: t.str, content: t.str, tags: t.array(t.str), published: t.bool, createdAt: t.num.options({format: 'u64'}), author: t.object({ id: t.str, name: t.str, }), }); const CreatePostResponse = t.object({ success: t.bool, post: Post, }).optional({ error: t.str, }); // Extract TypeScript types using t.infer type PostType = t.infer<typeof Post>; type CreateRequestType = t.infer<typeof CreatePostRequest>; type CreateResponseType = t.infer<typeof CreatePostResponse>; // Now you have full type safety! const newPost: PostType = { id: "123", title: "My Blog Post", content: "This is the content...", tags: ["typescript", "json"], published: true, createdAt: Date.now(), author: { id: "user456", name: "John Doe" } };

Usage

Type builder for JSON-like data structures:

import {t} from '@jsonjoy.com/json-type'; t.String(); // { kind: 'str' } t.String({const: 'add'}); // { kind: 'str', const: 'add' } const type = t.Object([ t.Field( 'collection', t.Object([ t.Field('id', t.String({format: 'ascii', noJsonEscape: true})), t.Field('ts', t.num, {format: 'u64'}), t.Field('cid', t.String({format: 'ascii', noJsonEscape: true})), t.Field('prid', t.String({format: 'ascii', noJsonEscape: true})), t.Field('slug', t.String({format: 'ascii', noJsonEscape: true})), t.Field('name', t.str, {isOptional: true}), t.Field('src', t.str, {isOptional: true}), t.Field('doc', t.str, {isOptional: true}), t.Field('authz', t.str, {isOptional: true}), t.Field('active', t.bool), ]), ), t.Field( 'block', t.Object([ t.Field('id', t.String({format: 'ascii', noJsonEscape: true})), t.Field('ts', t.num, {format: 'u64'}), t.Field('cid', t.String({format: 'ascii', noJsonEscape: true})), t.Field('slug', t.String({format: 'ascii', noJsonEscape: true})), ]), ), ]);

Node Types

JSON Type provides a comprehensive set of node types for modeling JSON-like data structures. Each node type has a kind property that identifies its type, along with specific properties and constraints.

Core Types

AnySchema (any)

Represents data of unknown type.

interface AnySchema { kind: 'any'; validator?: string | string[]; // Custom validation rules metadata?: Record<string, unknown>; // Custom metadata }

Example:

s.Any() // { kind: 'any' }

BooleanSchema (bool)

Represents a JSON boolean value.

interface BooleanSchema { kind: 'bool'; validator?: string | string[]; // Custom validation rules }

Example:

s.Boolean() // { kind: 'bool' }

NumberSchema (num)

Represents a JSON number with optional format and range constraints.

interface NumberSchema { kind: 'num'; format?: 'i' | 'u' | 'f' | 'i8' | 'i16' | 'i32' | 'i64' | 'u8' | 'u16' | 'u32' | 'u64' | 'f32' | 'f64'; gt?: number; // Greater than (exclusive) gte?: number; // Greater than or equal to lt?: number; // Less than (exclusive) lte?: number; // Less than or equal to validator?: string | string[]; }

Format options:

  • i* - Signed integers (i8, i16, i32, i64)
  • u* - Unsigned integers (u8, u16, u32, u64)
  • f* - Floating point (f32, f64)

Examples:

s.Number() // { kind: 'num' } s.Number({format: 'u32'}) // 32-bit unsigned integer s.Number({gte: 0, lte: 100}) // Number between 0 and 100

StringSchema (str)

Represents a JSON string with optional format and length constraints.

interface StringSchema { kind: 'str'; format?: 'ascii' | 'utf8'; // Character encoding format ascii?: boolean; // @deprecated Use format: 'ascii' noJsonEscape?: boolean; // Skip JSON escaping for performance min?: number; // Minimum length max?: number; // Maximum length validator?: string | string[]; }

Examples:

s.String() // { kind: 'str' } s.String({format: 'ascii'}) // ASCII-only string s.String({min: 1, max: 50}) // String with length constraints s.String({format: 'ascii', noJsonEscape: true}) // Optimized ASCII string

BinarySchema (bin)

Represents binary data with an encoded type.

interface BinarySchema { kind: 'bin'; type: TType; // Type of value encoded in binary format?: 'json' | 'cbor' | 'msgpack' | 'resp3' | 'ion' | 'bson' | 'ubjson' | 'bencode'; min?: number; // Minimum size in bytes max?: number; // Maximum size in bytes validator?: string | string[]; }

Examples:

s.Binary(s.String()) // Binary-encoded string s.Binary(s.Object(), {format: 'cbor'}) // CBOR-encoded object

Composite Types

ArraySchema (arr)

Represents a JSON array with elements of a specific type.

interface ArraySchema { kind: 'arr'; type: TType; // Type of array elements min?: number; // Minimum number of elements max?: number; // Maximum number of elements validator?: string | string[]; }

Examples:

s.Array(s.String()) // Array of strings s.Array(s.Number(), {min: 1, max: 10}) // Array with 1-10 numbers

TupleSchema (tup)

Represents a fixed-length array with specific types for each position.

interface TupleSchema { kind: 'tup'; types: TType[]; // Types for each position validator?: string | string[]; }

Example:

s.Tuple(s.String(), s.Number(), s.Boolean()) // [string, number, boolean]

ObjectSchema (obj)

Represents a JSON object with defined fields.

interface ObjectSchema { kind: 'obj'; keys: ObjectKeydSchema[]; // Defined object keys decodeUnknownKeys?: boolean; encodeUnknownKeys?: boolean; validator?: string | string[]; }

Examples:

s.Object([ s.prop('name', s.String()), s.propOpt('age', s.Number()) // Optional field ])

ObjectKeySchema (key)

Represents a single field in an object.

interface ObjectKeydSchema { kind: 'key'; key: string; // Field name type: TType; // Field value type optional?: boolean; // Whether field is optional }

Examples:

s.prop('id', s.String()) // Required field s.propOpt('description', s.String()) // Optional field

MapSchema (map)

Represents an object treated as a map with string keys and uniform value types.

interface MapSchema { kind: 'map'; type: TType; // Type of all values validator?: string | string[]; }

Example:

s.Map(s.Number()) // Object with number values

Advanced Types

ConstSchema (const)

Represents a constant value.

interface ConstSchema { kind: 'const'; value: any; // The constant value validator?: string | string[]; }

Examples:

s.Const('hello' as const) // Constant string s.Const(42 as const) // Constant number s.Const(null) // Null constant

RefSchema (ref)

References another type by ID.

interface RefSchema { kind: 'ref'; ref: string; // ID of referenced type }

Example:

s.Ref('UserType') // Reference to type with ID 'UserType'

OrSchema (or)

Represents a union type (one of multiple possible types).

interface OrSchema { kind: 'or'; types: TType[]; // Possible types discriminator: Expr; // Expression to determine type }

Example:

s.Or(s.String(), s.Number()) // String or number

FunctionSchema (fn)

Represents a function type with request and response.

interface FunctionSchema { kind: 'fn'; req: TType; // Request type res: TType; // Response type }

Example:

s.Function(s.String(), s.Number()) // Function: string -> number

FunctionStreamingSchema (fn$)

Represents a streaming function type.

interface FunctionStreamingSchema { kind: 'fn$'; req: TType; // Request stream type res: TType; // Response stream type }

Example:

s.Function$(s.String(), s.Number()) // Streaming function

Common Properties

All node types extend the base TType interface with these common properties:

interface TType { kind: string; // Node type identifier // Display properties title?: string; // Human-readable title intro?: string; // Short description description?: string; // Long description (may include Markdown) // Metadata id?: string; // Unique identifier meta?: Record<string, unknown>; // Custom metadata examples?: TExample[]; // Usage examples // Deprecation deprecated?: { description?: string; // Deprecation reason and alternative }; }

Validation

Many types support custom validation through the validator property:

// Single validator { validator: 'email' } // Multiple validators { validator: ['required', 'email'] }

Validation rules are applied using the JSON Expression language for flexible custom constraints.

About

JSON Type implementation. Fast JSON data type schema validation with JIT compilation.

Resources

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published

Contributors 2

  •  
  •