Giter VIP home page Giter VIP logo

value-schema's Introduction

value-schema

Build Status (Windows) Build Status (macOS) Build Status (Linux) Code Coverage Release Node.js version TypeScript version Deno version Bun version License

simple, easy-to-use, and declarative input validator

supports Node.js, TypeScript, Deno, and Bun

Table of Contents


Introduction

All of web applications need handling input parameters, consists of following steps:

  1. existence check
    • all required parameters exist?
    • fill omittable parameters with default values
  2. type check
    • e.g., typeof age === "number"
    • cast them if needed; "20"(string) to 20(number)
  3. domain check
    • e.g., 1 <= limit && limit <= 100
    • revise them if needed; 0 to 1

value-schema does all of them, by compact and highly readable code!

example

import vs from "value-schema";

const schemaObject = { // schema for input
    id: vs.number({ // number, >=1
        minValue: 1,
    }),
    name: vs.string({ // string, max 16 characters (trims if over)
        maxLength: {
            length: 16,
            trims: true,
        },
    }),
    birthday: vs.date(), // Date
    age: vs.number({ // number, integer (rounds down toward zero), >=0
        integer: vs.NUMBER.INTEGER.FLOOR_RZ,
        minValue: 0,
    }),
    email: vs.email(), // email
    state: vs.string({ // string, accepts only "active" and "inactive"
        only: ["active", "inactive"],
    }),
    classes: vs.array({ // array of number, separated by ",", ignores errors
        separatedBy: ",",
        each: {
            schema: vs.number(),
            ignoresErrors: true,
        },
    }),
    skills: vs.array({ // array of string, separated by ",", ignores errors
        separatedBy: ",",
        each: {
            schema: vs.string(),
            ignoresErrors: true,
        },
    }),
    creditCard: vs.numericString({ // numeric string, separated by "-", checks by Luhn algorithm
        separatedBy: "-",
        checksum: vs.NUMERIC_STRING.CHECKSUM_ALGORITHM.CREDIT_CARD,
    }),
    remoteAddr: vs.string({ // IPv4
        pattern: vs.STRING.PATTERN.IPV4,
    }),
    remoteAddrIpv6: vs.string({ // IPv6
        pattern: vs.STRING.PATTERN.IPV6,
    }),
    limit: vs.number({ // number, integer, omittable (sets 10 if omitted), >=1 (sets 1 if less), <=100 (sets 100 if greater)
        ifUndefined: 10,
        integer: true,
        minValue: {
            value: 1,
            adjusts: true,
        },
        maxValue: {
            value: 100,
            adjusts: true,
        },
    }),
    offset: vs.number({ // number, integer, omittable (sets 0 if omitted), >=0 (sets 0 if less)
        ifUndefined: 0,
        integer: true,
        minValue: {
            value: 0,
            adjusts: true,
        },
    }),
};
const input = { // input values
    id: "1",
    name: "Pablo Diego José Francisco de Paula Juan Nepomuceno María de los Remedios Ciprin Cipriano de la Santísima Trinidad Ruiz y Picasso",
    birthday: "2000-01-02T03:04:05.678Z",
    age: 20.5,
    email: "[email protected]",
    state: "active",
    classes: "1,3,abc,4",
    skills: "c,c++,javascript,python,,swift,kotlin",
    creditCard: "4111-1111-1111-1111",
    remoteAddr: "127.0.0.1",
    remoteAddrIpv6: "::1",
    limit: "0",
};
const expected = { // should be transformed to this
    id: 1,
    name: "Pablo Diego José",
    birthday: new Date("2000-01-02T03:04:05.678Z"),
    age: 20,
    email: "[email protected]",
    state: "active",
    classes: [1, 3, 4],
    skills: ["c", "c++", "javascript", "python", "swift", "kotlin"],
    creditCard: "4111111111111111",
    remoteAddr: "127.0.0.1",
    remoteAddrIpv6: "::1",
    limit: 1,
    offset: 0,
};

// Let's apply!
const actual = vs.applySchemaObject(schemaObject, input);

// verification
assert.deepStrictEqual(actual, expected);

That's all! No control flows! Isn't it cool?

For details, see reference.

Install

install from npm registry.

npm install -S value-schema

Loading

CommonJS

// foo.js
var vs = require("value-schema");

ES Modules / Babel / TypeScript

// foo.mjs (ES Modules) / foo.js (Babel) / foo.ts (TypeScript)
import vs from "value-schema";

ES Modules has been supported as of Node.js v8.5.0. In Windows, Node.js v8.6.0 is recommended due to ERR_INVALID_PROTOCOL.

To execute "foo.mjs", --experimental-modules flag is required. (the flag is dropped as of Node.js v13.2.0)

$ node --experimental-modules foo.mjs
(node:25508) ExperimentalWarning: The ESM module loader is experimental.

TypeScript auto-completion and type-checking works perfectly on Visual Studio Code and IntelliJ IDEA!

Deno has been supported as of v3.

// use latest version
import vs from "https://deno.land/x/value_schema/mod.ts";
// use specific version
import vs from "https://deno.land/x/[email protected]/mod.ts";

CAUTION: specify value_schema (underscore) NOT value-schema (hyphen) because deno.land module database does not support name with hyphen!

Bun has been supported as of v4, but might work v3 or earlier.

Use just like a npm module.

import vs from "value-schema";

Changelog

See CHANGELOG.md.

value-schema's People

Contributors

shimataro avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

value-schema's Issues

Union type

Like this:

import assert from "assert";
import vs from "value-schema";

// accepts both number and integer
const schema = vs.union({
    schemas: [vs.number(), vs.string()],
});

assert.strictEqual(schema.applyTo(1), 1);
assert.strictEqual(schema.applyTo("a"), "a");

v3 plan

Planning more simple and easy-to-understand interface in v3.

i.e.,

// in v2
import vs from "value-schema";
vs.number()
    .strict()
    .default(0)
    .acceptNull(null)
    .acceptEmptyString(null)
    .acceptSpecialFormats()
    .acceptFullWidth()
    .integer(true)
    .only(0, 1, 2, 3)
    .minValue(0, true)
    .maxValue(3, false);
// in v3
import vs from "value-schema";
vs.number({
    strict: true,
    acceptsSpecialFormats: true,
    acceptsFullWidth: true,
    default: 0,
    ifNull: null,
    ifEmptyString: null,
    integer: {
        adjusts: true,
    },
    only: [0, 1, 2, 3],
    minValue: {
        value: 0,
        adjusts: true,
    },
    maxValue{
        value: 3,
        adjusts: false,
    },
});

Deno/Typescript example doesn't work

Deno version: 1.5.2 (using the hayd/deno:1.5.2 dockerfile)
value-schema version: 3.0.0, imported from https://deno.land/x/value_schema/mod.ts.

interface Parameters {
    foo: number;
    bar: string;
}

const schemaObject = {
    foo: vs.number(),
    bar: vs.string(),
};
const input = {
    foo: "12345",
    bar: "abcde",
};

const actual = vs.applySchemaObject<Parameters>(schemaObject, input);

Compiling with this code gives the error:

error: TS2344 [ERROR]: Type 'Parameters' does not satisfy the constraint 'Record<string, BaseSchema<unknown>>'.
  Index signature is missing in type 'Parameters'.
const actual = vs.applySchemaObject<Parameters>(schemaObject, input);

To solve this, I imported BaseSchema from https://deno.land/x/[email protected]/dist-deno/schemaClasses/BaseSchema.ts and updated my code to include an index in the Parameters interface:

interface Parameters {
    foo: number;
    bar: string;
    [key: string]: BaseSchema<unknown>
}

const schemaObject = {
    foo: vs.number(),
    bar: vs.string(),
};
const input = {
    foo: "12345",
    bar: "abcde",
};

const actual = vs.applySchemaObject<Parameters>(schemaObject, input);

This updated resulted in the following build errors:

error: TS2411 [ERROR]: Property 'foo' of type 'number' is not assignable to string index type 'BaseSchema<unknown>'.
    foo: number;
    ~~~
    at file:///home/dev/reports/index.ts:12:5

TS2411 [ERROR]: Property 'bar' of type 'string' is not assignable to string index type 'BaseSchema<unknown>'.
    bar: string;
    ~~~
    at file:///home/dev/reports/index.ts:13:5

TS2345 [ERROR]: Argument of type '{ foo: NumberSchema<never>; bar: StringSchema<never>; }' is not assignable to parameter of type 'Parameters'.
  Types of property 'foo' are incompatible.
    Type 'NumberSchema<never>' is not assignable to type 'number'.
const actual = vs.applySchemaObject<Parameters>(schemaObject, input);
                                                ~~~~~~~~~~~~
    at file:///home/dev/reports/index.ts:26:49

Found 3 errors.

Finally, I imported the NumberSchema and StringSchema types in an attempt to fully satisfy the typechecker. The final code was:

interface Parameters {
    foo: NumberSchema;
    bar: StringSchema;
    [key: string]: BaseSchema<unknown>
}

const schemaObject = {
    foo: vs.number(),
    bar: vs.string(),
};
const input = {
    foo: "12345",
    bar: "abcde",
};

const actual = vs.applySchemaObject<Parameters>(schemaObject, input);

This works, but I'd rather not have to specify the NumberSchema, StringSchema, and BaseSchema types at all, as per the example on the README. Is there a simpler update I can do to make this work with the interface without importing all of those types?

Let me know if I can provide any more info, thanks!

Not compatible with Deno 1.21

The ValueSchemaError is not type compatible with at least Deno 1.21

TS2416 [ERROR]: Property 'cause' in type 'ValueSchemaError' is not assignable to the same property in base type 'Error'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.