All Projects → open-draft → reach-schema

open-draft / reach-schema

Licence: MIT license
Functional schema-driven JavaScript object validation library.

Programming Languages

typescript
32286 projects
javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to reach-schema

Password Validator
Validates password according to flexible and intuitive specification
Stars: ✭ 224 (+558.82%)
Mutual labels:  schema, validate, validation-library
metaschema
Schema definition and validation 💡
Stars: ✭ 25 (-26.47%)
Mutual labels:  schema, validate
volder
volder is powerful Object schema validation lets you describe your data using a simple and readable schema and transform a value to match the requirements
Stars: ✭ 106 (+211.76%)
Mutual labels:  schema, validation-library
fefe
Validate, sanitize and transform values with proper TypeScript types and zero dependencies.
Stars: ✭ 34 (+0%)
Mutual labels:  schema, validate
Vee Validate
✅ Form Validation for Vue.js
Stars: ✭ 8,820 (+25841.18%)
Mutual labels:  validate, validation-library
Nager.publicsuffix
.NET publicsuffix domain parser
Stars: ✭ 67 (+97.06%)
Mutual labels:  validate, validation-library
tyshemo
A javascript runtime data type checking system and morden reactive state management model.
Stars: ✭ 70 (+105.88%)
Mutual labels:  schema, validate
normalize-pkg
Normalize values in package.json to improve compatibility, programmatic readability and usefulness with third party libs.
Stars: ✭ 18 (-47.06%)
Mutual labels:  schema, object
Fastest Validator
⚡️ The fastest JS validator library for NodeJS
Stars: ✭ 923 (+2614.71%)
Mutual labels:  schema, validate
Framework
Strongly-typed JavaScript object with support for validation and error handling.
Stars: ✭ 136 (+300%)
Mutual labels:  schema, object
Nope Validator
A small, simple and fast JS validator. Like, wow thats fast. 🚀
Stars: ✭ 142 (+317.65%)
Mutual labels:  schema, object
vayder
Easy and concise validations for Express routes
Stars: ✭ 26 (-23.53%)
Mutual labels:  validate, validation-library
FilterInputJs
Tiny and Powerful Library for limit an entry (text box,input) as number,string or more...
Stars: ✭ 37 (+8.82%)
Mutual labels:  validate, validation-library
Php Validate
Lightweight and feature-rich PHP validation and filtering library. Support scene grouping, pre-filtering, array checking, custom validators, custom messages. 轻量且功能丰富的PHP验证、过滤库。支持场景分组,前置过滤,数组检查,自定义验证器,自定义消息。
Stars: ✭ 225 (+561.76%)
Mutual labels:  validate, validation-library
Schm
Composable schemas for JavaScript and Node.js
Stars: ✭ 498 (+1364.71%)
Mutual labels:  schema, validate
schemaglue
Naturally breaks down your monolithic graphql schema into bits and pieces and then glue them back together.
Stars: ✭ 117 (+244.12%)
Mutual labels:  resolver, schema
graphql-tutorial
Tutorial for GraphQL
Stars: ✭ 24 (-29.41%)
Mutual labels:  resolver, schema
schema-and-structured-data-for-wp
Creating the best Structured Data and Schema plugin for WordPress
Stars: ✭ 66 (+94.12%)
Mutual labels:  schema
magnet
A JSON/BSON schema generator
Stars: ✭ 16 (-52.94%)
Mutual labels:  schema
sbt-avro
Plugin SBT to Generate Scala classes from Apache Avro schemas hosted on a remote Confluent Schema Registry.
Stars: ✭ 15 (-55.88%)
Mutual labels:  schema

Reach schema logo


Reach Schema

Functional schema-driven JavaScript object validation library.

Motivation

It happens that JavaScript Object validation libraries are often class-based and operate using via a chain of operators. With Reach Schema I would like to take an alternative approach, making validation functional.

Main concepts of React Schema:

  1. Validation result is a function from schema and data.
  2. Validation result is not coupled with the error messages logic.

Reach Schema works great together with functional programming libraries like lodash or ramda. They allow to make validation declaration shorter and make your life easier. Consider those.

Validation schema

Data validity is described using a validation schema. It's a plain Object which keys represent the actual data keys hierarhcy, and values equal to resolver functions that return the validation verdict.

interface Schema {
  [field: string]: Resolver | NamedResolver | Schema
}

// A plain resolver function that returns a boolean verdict.
interface Resolver<ValueType> {
  (value: ValueType): boolean
}

// A named resolver function that returns a Record of rules.
interface NamedResolver<ValueType> {
  (value: ValueType): {
    [ruleName: string]: boolean
  }
}

Applying a validation schema to the actual data returns the validation result.

interface ValidationResult {
  errors: Error[]
}

Resolver

Resolver is a function that determines a value's validity. A simple resolver accepts a value and returns a boolean verdict. Reach Schema supports more complex resolvers, such as grouped resolver, which allows to provide multiple independent criteria to a single value.

Basic resolver

useSchema(
  {
    firstName: (value, pointer) => value === 'John',
  },
  {
    firstName: 'Jessica',
  },
)

Grouped resolver

useSchema(
  {
    password: (value, pointer) => ({
      minLength: value.length > 7,
      capitalLetter: /[A-Z]/.test(value),
      oneNumber: /[0-9]/.test(value),
    }),
  },
  {
    password: 'IshallPass8',
  },
)

Nested schema

Resolver may also return an Object, if validating an Object type value, which would be treated as a nested Validation schema.

useSchema(
  {
    billingDetails: {
      // Nested schema accepts all kinds of resolvers:
      // basic, grouped, and deeply nested schema.
      address: (value) => checkAddressExistance(value),
      zipCode: (value) => /\d{5}/.test(zipCode),
    },
  },
  {
    billingDetails: {
      address: 'Sunwell Ave.',
      zipCode: 56200,
    },
  },
)

Errors

Each validation error has the following structure:

interface Error {
  // Pointer to the related property in the actual data.
  pointer: string[]

  // A property's validation state.
  // - "missing". Expected, but not present in the actual data.
  // - "invalid". Present, but doesn't satisfy the validation resolver.
  status: 'missing' | 'invalid'

  // A property's value, if present in the actual data.
  value?: any

  // Name of the rejected validation rule, if applicable.
  rule?: string
}

API

useSchema: (schema: Schema, data: Object): ValidationError[]

Basic example

Each key in a schema corresponds to same property in the actual data. Each schema value is a resolver function that accepts an actual data value and returns a Boolean verdict.

import { useSchema } from 'reach-schema'

useSchema(
  {
    firstName: (value) => value === 'john',
    lastName: (value) => value === 'locke',
    age: (value) => value > 17,
  },
  {
    firstName: 'john',
    age: 16,
  },
)
[
  {
    "pointer": ["lastName"],
    "status": "missing"
  },
  {
    "pointer": ["age"],
    "status": "invalid",
    "value": 16
  }
]

Nested properties

If a schema key equals an Object literal, that nested Object is expected in the data. This allows to validate deeply nested structures.

import { useSchema } from 'reach-schema'

useSchema(
  {
    billingData: {
      country: (value) => ['UK', 'ES'].includes(value),
    },
  },
  {
    billingData: {
      country: 'US',
    },
  },
)
[
  {
    "pointer": ["billingData", "country"],
    "status": "invalid",
    "value": "US"
  }
]

Multiple criteria

A resolver function may also return a map of rules that apply to the corresponding nested properties. By default, the actual value must satisfy all the rules in order to be valid (see Optional validation). Each resolver corresponding to a validation criteria is called named resolver.

import { useSchema } from 'reach-schema'

useSchema(
  {
    password: (value) => ({
      minLength: value.length > 5,
      capitalLetters: /[A-Z]{2}/.test(value),
      oneNumber: /[0-9]/.test(value),
    }),
  },
  {
    password: 'DeMo',
  },
)
[
  {
    "pointer": ["password"],
    "status": "invalid",
    "value": "DeMo",
    "rule": "minLength"
  },
  {
    "pointer": ["password"],
    "status": "invalid",
    "value": "DeMo",
    "rule": "oneNumber"
  }
]

Error messages

Reach Schema does not provide any error messages directly. Instead, it treats an error message as an artifact derived from the validation result. To achieve that it provides all the relevant information in the validation result to construct an error message.

However, there is a common logic that can be integrated into such error messages construction (i.e. resolving due to priority, fallback messages). Declaring such logic each time would be lengthy, time-consuming, and prone to human error.

Recipes

Property existence

To check that a property exists in the actual data provide a resolver function that always returns true. Ideologically it marks the property as "always valid", but since the default validation behavior asserts all the keys present in the Validation Schema, it also implies that the property must be present.

import { useSchema } from 'reach-schema'

useSchema(
  {
    // The property "email" is required in the data Object,
    // but is always valid, no matter the value.
    email: () => true,
  },
  {
    email: '[email protected]',
  },
)

Optional validation

To apply an optional (weak) validation to a property wrap its resolver in the optional helper function. This way the property's value will be validated only if present in the actual data. If the property is missing in the actual data it's never validated and considered as valid.

import { useSchema, optional } from 'reach-schema'

useSchema(
  {
    firstName: optional((value) => value.length > 1),
    billingData: optional({
      address: (value) => value.includes('st.'),
      firstName: optional((value) => value.length > 1),
    }),
  },
  {
    billingData: {
      address: 'Invalid address',
      firstName: 'J',
    },
  },
)
[
  {
    "pointer": ["billingData", "address"],
    "status": "invalid",
    "value": "Invalid address"
  },
  {
    "pointer": ["billingData", "firstName"],
    "status": "invalid",
    "value": "J"
  }
]

Usage with TypeScript

useSchema will infer the type of the given data automatically. However, to type guard the data itself it's useful to describe the data separately and provide to schema:

interface UserDetails {
  firstName: string
  lastName: string
  age: number
}

useSchema<UserDetails>(
  {
    firstName: (value) => value.length > 2,
    lastName: (value) => value.length > 2,
    age: (value) => value > 17,
  },
  {
    firstName: 'John',
    lastName: 'Maverick',
    age: 31,
  },
)
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].