{"id":22503654,"url":"https://github.com/jokero/validy","last_synced_at":"2026-03-11T11:38:26.953Z","repository":{"id":57390451,"uuid":"48305126","full_name":"Jokero/validy","owner":"Jokero","description":"Declarative validation with async validators support","archived":false,"fork":false,"pushed_at":"2018-08-27T11:54:27.000Z","size":111,"stargazers_count":12,"open_issues_count":3,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-04-23T22:19:26.225Z","etag":null,"topics":["asynchronous","declarative","schema","validate","validation","validator"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Jokero.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-12-20T02:54:36.000Z","updated_at":"2022-11-16T19:45:48.000Z","dependencies_parsed_at":"2022-09-15T06:12:09.463Z","dependency_job_id":null,"html_url":"https://github.com/Jokero/validy","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jokero%2Fvalidy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jokero%2Fvalidy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jokero%2Fvalidy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Jokero%2Fvalidy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Jokero","download_url":"https://codeload.github.com/Jokero/validy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228540810,"owners_count":17934029,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asynchronous","declarative","schema","validate","validation","validator"],"created_at":"2024-12-06T23:37:21.724Z","updated_at":"2026-03-11T11:38:26.909Z","avatar_url":"https://github.com/Jokero.png","language":"JavaScript","readme":"# validy\n\nDeclarative validation with async validators support.\nIf you also want to work with filters and default values, take a look at [transformer-chain](https://github.com/Jokero/transformer-chain).\nYou may be interested in express middleware ([express-request-parameters](https://github.com/Jokero/express-request-parameters)) useful for HTTP API.\n\n[![NPM version](https://img.shields.io/npm/v/validy.svg)](https://npmjs.org/package/validy)\n[![Build status](https://img.shields.io/travis/Jokero/validy.svg)](https://travis-ci.org/Jokero/validy)\n\n**Note:** This module works in browsers and Node.js \u003e= 4.0. Use `Object.assign` and `Promise` polyfills for Internet Explorer\n\n## Table of Contents\n\n- [Demo](#demo)\n- [Installation](#installation)\n  - [Node.js](#nodejs)\n  - [Browser](#browser)\n- [Overview](#overview)\n- [Usage](#usage)\n  - [validy(object, schema, [options])](#validyobject-schema-options)\n    - [Parameters](#parameters)\n    - [Return value](#return-value)\n  - [Validators](#validators)\n    - [Built-in validators](#built-in-validators)\n    - [Custom validator](#custom-validator)\n      - [Synchronous validator](#synchronous-validator)\n      - [Asynchronous validator](#asynchronous-validator)\n  - [Error format](#error-format)\n  - [Error messages](#error-messages)\n  - [Return value](#return-value-1)\n  - [Dynamic schema](#dynamic-schema)\n- [Build](#build)\n- [Tests](#tests)\n- [License](#license)\n\n## Demo\n\nTry [demo](https://runkit.com/npm/validy) on RunKit.\n\n## Installation\n\n```sh\nnpm install validy\n```\n\n### Node.js\n```js\nconst validy = require('validy');\n```\n\n### Browser\n```\n\u003cscript src=\"node_modules/validy/dist/validy.js\"\u003e\n```\nor minified version\n```\n\u003cscript src=\"node_modules/validy/dist/validy.min.js\"\u003e\n```\n\nYou can use the module with AMD/CommonJS or just use `window.validy`.\n\n## Overview\n\n`validy` allows you to validate flat and nested objects using collection of default validators and your own validators. \n\nValidators can be asynchronous, you can do DB calls for example and so on.\n\nTo validate object you should define schema. It's simple object with your constraints:\n\n```js\nconst book = { // object to validate\n    name: 'The Adventures of Tom Sawyer',\n    author: {\n        name: 'Mark Twain'\n    },\n    reviews: [\n        {\n            author: 'Leo Tolstoy',\n            text: 'Great novel'\n        },\n        {\n            author: 'Fyodor Dostoyevsky',\n            text: 'Very interesting'\n        }\n    ]\n};\n\nconst schema = {\n    name: {\n        $validate: {\n            required: true,\n            string: true\n        }\n    },\n    author: {\n        $validate: { // you can omit check that \"author\" value is object, it will be done internally \n            required: true\n        },\n    \n        name: {\n            $validate: {\n                required: true,\n                string: true\n            }\n        }\n    },\n    reviews: [{ // define schema for array items\n        author: {\n            $validate: {\n                required: true,\n                string: true\n            }\n        },\n        text: {\n            $validate: {\n                required: true,\n                string: true\n            }\n        }\n    }]\n};\n\nvalidy(book, schema)\n    .then(errors =\u003e {\n        if (errors) {\n            // you have validation errors (\"errors\" is plain object)\n        } else {\n            // no errors (\"errors\" is undefined)\n        }\n    })\n    .catch(err =\u003e {\n        // application error (something went wrong)\n    });\n\n// async/await example\nasync function example() {\n    try {\n        const errors = await validy(book, schema);\n        if (errors) {\n            // you have validation errors (\"errors\" is plain object)\n        } else {\n            // no errors (\"errors\" is undefined)\n        }\n    } catch(err) {\n        // application error (something went wrong)\n    }\n}\n```\n\n## Usage\n\n### validy(object, schema, [options])\n\n#### Parameters\n\n- `object` (Object) - Object to validate\n- `schema` (Object) - Schema which defines how to validate object\n- `[options]` (Object) - Validation options\n    - `[format=flat]` (string) - Format of object with validation errors (`flat`, `nested`)\n    - `[reject=false]` (boolean) - Should return fulfilled promise with errors (`by default`) or rejected with `ValidationError`?\n\n#### Return value\n\n(Promise) - Result of validation. Promise is returned even for synchronous only validation\n\n### Validators\n\n#### Built-in validators\n\nBy default `validy` uses collection of simple and useful validators ([common-validators](https://github.com/tamtakoe/common-validators) module).\n\n**Note**:\nThe basic principle of built-in validators is that most of them (except `required`, `notEmpty` and type validators `object`, `array`, ...) consider empty values as **valid values**.\nEmpty values are:\n- `undefined`\n- `null`\n- `NaN`\n- `''`\n- `'   '` (whitespace only string)\n- `[]`\n- `{}`\n\nAlso they convert passed value to expected type. For example, `max` validator which checks that value is not greater than some limit will try to convert passed value to number (`Number(value)`).\nAll non-convertible values will be treated as `NaN` and validator will return validation error.\n\nSome of built-in validators:\n\n- **required (presence)** - validates that the value isn't `undefined`, `null`, `NaN`, empty or whitespace only string, empty array or object\n- **notEmpty** - like `required` but `undefined` is valid value. It is useful for PATCH requests\n- **object / array / string / number / integer / ...** - value is plain object, array, etc. `undefined` is valid value\n- **max** - value is less than maximum\n- **min** - value is greater than minimum\n- **range** - value is in range\n- **maxLength** - value length is greater than maximum\n- **minLength** - value length is greater than minimum\n- **pattern** - value matches the pattern\n- **inclusion** - value is contained in white list\n- **exclusion** - value is not contained in black list\n- **email** - value is email address\n- **url** - value is URL\n- and many others (see [common-validators#validators](https://github.com/tamtakoe/common-validators#validators))\n\n#### Custom validator\n\nYou can add your own validator:\n\n```js\nvalidy.validators.add('greaterThan', function(value, options) {\n    // validator implementation\n});\n\n// or\n\nvalidy.validators.add({ // this way you can add several validators at once\n    greaterThan: function(value, options) {\n        // validator implementation\n    },\n    anotherValidator: function(value, options) {\n        // validator implementation\n    }\n});\n```\n\nAlthough in most cases you will have only two parameters in your own validators (`value` and `options`), some situations will require a bit knowledgeable validator.\nSo, full signature of validator is:\n\n**validator(value, options, object, fullObject, path)**\n\n- `value` (any) - Validated value\n- `options` (Object) - Validator options\n- `object` (Object) - Object whose property is validated at the moment\n- `fullObject` (Object) - The whole validated object (object which was initially passed to `validy`)\n- `path` (string[]) - Path to property\n\nSo imagine you wrote `validateSomething` validator:\n\n```js\nconst book = {\n    name: 'The Adventures of Tom Sawyer',\n    author: {\n        name: 'Mark Twain'\n    }\n};\n\nconst schema = {\n    name: {\n        $validate: {\n            required: true,\n            string: true\n        }\n    },\n    author: { \n        $validate: {\n            required: true\n        },\n        \n        name: {\n            $validate: {\n                required: true,\n                string: true,\n                validateSomething: 'someArgument' // \u003c--- and you want to use it here\n            }\n        }\n    }\n};\n```\n\n`validateSomething` validator will be called with the following arguments:\n\n1) value\n\nValue of `author.name` property.\n```js\n'Mark Twain' \n```\n\n2) options\n\nWhen you use non-object value as validator options it will be wrapped in object with `arg` property.\n```js\n{\n    arg: 'someArgument'\n}\n```\n\n3) object\n\nObject with `name` property (`author` object).\n```js\n{\n    name: 'Mark Twain'\n}\n```\n\n4) fullObject\n\nThe whole validated object (`book` object).\n```js\n{\n    name: 'The Adventures of Tom Sawyer',\n    author: {\n        name: 'Mark Twain'\n    }\n}\n```\n\n5) path\n\n```js\n['author', 'name']\n```\n\n##### Synchronous validator\n\nExample:\n\n```js\nvalidy.validators.add('russianLettersOnly', function(value) {\n    // it's ok to consider empty value as valid value\n    // use \"required\" validator when this value must not be empty\n    if (value === '') {\n        // if value is valid just return nothing or falsy value \n        return;\n    }\n    \n    if (typeof value !== 'string' || !/^[а-яё]+$/i.test(value)) {\n        // when value is invalid, return string with error\n        return 'must contain only Russian letters';\n    }\n});\n\n// or\n\nvalidy.validators.add({ // this way you can add several validators at once\n    russianLettersOnly: function(value) { /**/ },\n    \n    anotherValidator: function(value) { /**/ }\n});\n```\n\nAnd then just use it as any other validator:\n\n```js\n{\n    name: {\n        $validate: {\n            // validator will be called only if its config is not equal to false/null/undefined \n            russianLettersOnly: true\n        }\n    }\n}\n```\n\n##### Asynchronous validator\n\nAlmost the same as synchronous validator, just return fulfilled promise:\n\n```js\nvalidy.validators.add({\n    /**\n     * Check using mongoose model that value exists in mongodb \n     * \n     * @param {string} value\n     * @param {Object} options\n     * @param {Object}   options.model - Mongoose model\n     * @param {string}   [options.field] - Which field to use for search\n     *\n     * @returns {Promise}\n     */\n    exists: function(value, options) {\n        const errorMessage = 'does not exist';\n        \n        if (value === '') { \n            return Promise.resolve();\n        }\n        \n        if (typeof value !== 'string') {\n            return Promise.resolve(errorMessage);\n        } \n    \n        const model = options.model;\n        const field = options.field || '_id';\n    \n        return model.count({ [field]: value })\n            .then(count =\u003e {\n                if (!count) {\n                    // if value is invalid, return fulfilled promise with validation error\n                    return Promise.resolve(errorMessage);\n                }\n            });\n    }\n});\n```\n### Error format\n\nIf there are no validation errors `validy` returns `undefined` as fulfillment value:\n\n```js\nvalidy(book, schema)\n    .then(errors =\u003e {\n        console.log(errors); // undefined\n    })\n```\n\nIf you have validation errors:\n\n```js\nconst book = {\n    name: '', // empty\n    author: {\n        name: 123456789 // not string\n    }\n};\n\nconst schema = {\n    name: {\n        $validate: {\n            required: true,\n            string: true\n        }\n    },\n    author: {\n        $validate: {\n            required: true\n        },\n        \n        name: {\n            $validate: {\n                required: true,\n                string: true\n            }\n        }\n    }\n};\n\nvalidy(book, schema)\n    .then(errors =\u003e {\n        console.log(errors);\n    })\n```\n\n`errors` has flat structure by default:\n\n```js\n{\n    name: [{ // errors are always placed in array\n        error: 'required', // validator name\n        message: 'Is required' // error message\n    }],\n    'author.name': [{\n        error: 'string', \n        message: 'Must be a string'\n    }]\n}\n```\n\nBut you can use nested structure:\n\n```js\nvalidy(book, schema, { format: 'nested' })\n    .then(errors =\u003e {\n        console.log(errors);\n    })\n```\n\n`errors` with nested structure:\n\n```js\n{ \n    name: [{ \n        error: 'required', \n        message: 'Is required' \n    }],\n    author: { \n        name: [{ \n            error: 'string', \n            message: 'Must be a string'\n        }]\n    }\n}\n```\n\n### Error messages\n\nYou can customize error message for specific property:\n\n```js\nconst schema = {\n    url: {\n        $validate: {\n            url: { // instead of { url: true }\n                message: 'invalid url' // message can be either string or function returning string\n            }\n        }\n    }\n};\n\nconst object = {\n    url: 'not-url'\n};\n\nvalidy(object, schema)\n    .then(errors =\u003e {\n        console.log(errors); // { url: [ { error: 'url', message: 'invalid url' } ] }\n    });\n```\n\nOr set default message for a validator:\n\n```js\nvalidy.validators.url.defaultOptions = { message: 'bad url' };\n\nconst schema = {\n    url: {\n        $validate: {\n            url: true\n        }\n    }\n};\n\nconst object = {\n    url: 'not-url'\n};\n\nvalidy(object, schema)\n    .then(errors =\u003e {\n        console.log(errors); // { url: [ { error: 'url', message: 'bad url' } ] }\n    });\n\n```\n\n### Return value \n\nBy default `validy` returns fulfilled promise when validated object is not valid.\nIf for some reasons you want to use rejected promise with validation error instead of fulfilled promise, specify `reject` option:\n\n```js\nvalidy(object, schema, { reject: true })\n    .then(() =\u003e {\n        // no errors, everything is valid\n    })\n    .catch(err =\u003e {\n        if (err instanceof validy.ValidationError) {\n            // err.errors contains validation errors\n        } else {\n            // application error (something went wrong)            \n        }\n    });\n```\n\n### Dynamic schema\n\nSometimes you may need a way to validate some property differently depending on specific conditions.\nExample with order of various products:\n\n```js\nconst order = {\n    products: [\n        {\n            type: 'book',\n            name: 'The Adventures of Tom Sawyer',\n            count: 1\n        },\n        {\n            type: 'sugar',\n            weight: 3000\n        }\n    ]\n};\n\nconst productsSchemas = {\n    book: {\n        name: {\n            $validate: {\n                required: true,\n                string: true\n            }\n        },\n        count: {\n            $validate: {\n                required: true,\n                integer: true,\n                min: 1\n            }\n        }\n    },\n\n    sugar: {\n        weight: {\n            $validate: {\n                required: true,\n                integer: true,\n                min: 1000\n            }\n        }\n    }\n};\n\nconst schema = {\n    products: [(product/*, products, order, pathToItem*/) =\u003e {\n        const productSchema = productsSchemas[product.type];\n        return Object.assign({}, productSchema, {\n            type: {\n                $validate: {\n                    required: true,\n                    string: true,\n                    inclusion: Object.keys(productsSchemas)\n                }\n            }\n        });\n    }]\n};\n\n// or you can do like this (products is marked as required)\n\nconst alternativeSchema = {\n    products: {\n        $validate: { // validate also \"products\" before items validation\n            required: true,\n            array: true\n        },\n\n        $items: function(product/*, products, order, pathToItem*/) {\n            const productSchema = productsSchemas[product.type] || {};\n            return Object.assign({}, productSchema, {\n                type: {\n                    $validate: {\n                        required: true,\n                        string: true,\n                        inclusion: Object.keys(productsSchemas)\n                    }\n                }\n            });\n        }\n    }\n};\n```\n\nYou can do similar things with `$validate` and specific validator:\n\n```js\nconst bookSchema = {\n    author: {\n        name: {\n            $validate: function(name, author, book, pathToName) {\n                // implement your custom logic\n                \n                // validation will only run if you return object\n                // so you can return null for example to skip validation \n                return {\n                    required: function(name, author, book, pathToName) {\n                        // implement your custom logic\n                        // return undefined, null or false if you want skip validation\n                    },\n                    string: true\n                };\n            }\n        }\n    }\n};\n```\n\n## Build\n\n```sh\nnpm install\nnpm run build\n```\n\n## Tests\n\n```sh\nnpm install\nnpm test\n```\n\n## License\n\n[MIT](LICENSE)","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjokero%2Fvalidy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjokero%2Fvalidy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjokero%2Fvalidy/lists"}