{"id":13837160,"url":"https://github.com/ashtonsix/redux-validate","last_synced_at":"2025-07-10T16:32:21.396Z","repository":{"id":96886641,"uuid":"48478361","full_name":"ashtonsix/redux-validate","owner":"ashtonsix","description":"Easy validation for redux-form","archived":false,"fork":false,"pushed_at":"2016-08-05T15:51:05.000Z","size":29,"stargazers_count":20,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-08-05T15:05:38.604Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ashtonsix.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2015-12-23T08:14:03.000Z","updated_at":"2020-06-03T11:39:12.000Z","dependencies_parsed_at":null,"dependency_job_id":"99439159-8c34-4809-96b4-d4ca90f8a61a","html_url":"https://github.com/ashtonsix/redux-validate","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashtonsix%2Fredux-validate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashtonsix%2Fredux-validate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashtonsix%2Fredux-validate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashtonsix%2Fredux-validate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ashtonsix","download_url":"https://codeload.github.com/ashtonsix/redux-validate/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225648349,"owners_count":17502175,"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":[],"created_at":"2024-08-04T15:01:02.311Z","updated_at":"2024-11-20T23:32:27.150Z","avatar_url":"https://github.com/ashtonsix.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# redux-validate\n\nEasy validation optimized for [redux-form](https://github.com/erikras/redux-form). Also suitable for props/state validation/testing.\n\n`npm i redux-validate`\n\n## Quick Start\n\n```js\nimport validate from 'redux-validate';\n\nreduxForm({\n  ...\n  validate: validate(['title', 'description']) // {title: 'Code Geass', description: ''} =\u003e\n})(Component)                                  // {description: 'Description is required'}\n```\n\n## Complete Guide\n\nThere are many ways to use redux-validate, demonstrated below by example.\n\nYou can look at the tests for more examples.\n\n```js\nimport validate, {createValidate} from 'redux-validate';\n\n/*\ncreateValidate :: (defaultFunction) =\u003e validate\nvalidate :: (validator, defaultFunctionOverride) =\u003e (values, ...args) =\u003e errors\n\nIf validator is a function it will receive (values, ...args), in every other\ncase validators will be specific to one key and receive:\n  (value, key, values, ...args)\n\nIf using redux-plus:\n  \"...args\" = (props) for sync validation\n  \"...args\" = (dispatch, props) for async validation\n\nIf validator is synchronous, then errors is a plain object.\nIf validator is asynchronous, then errors is either:\n  \"Promise.resolve({})\" or \"Promise.reject(object)\"\n*/\n\nconst json = {\n  name: 'Ashford Academy',\n  headmaster: '',\n  location: '',\n  teachers: [\n    {name: '', students: {\n      Lelouch: {name: '', class: ''},\n      Suzaku: {name: '', class: 'Red'}}},\n    {name: 'Villetta Nu', students: [\n      {name: '', class: ''}]},\n    {name: '', students: []}\n  ]\n}\n\nlet errors\nlet customValidate\n\n// array of strings\nerrors = validate(['name', 'headmaster', 'location'])(json) =\n{headmaster: 'Headmaster is required', location: 'Location is required'}\n\n// one string\nerrors = validate('location')(json) =\n{location: 'Location is required'}\n\n// function\nerrors = validate(({teachers}) =\u003e {\n  if (teachers.find(({name}) =\u003e !name)) {\n    return {teachers: 'Every teacher must have a name'}\n  }\n})(json) =\n{teachers: 'Every teacher must have a name'}\n\n// object\u003cstring\u003e\nerrors = validate({location: 'Location is needed'})(json) =\n{location: 'Location is needed'}\n\n// object\u003cfunction\u003e\nerrors = validate({\n  name: name =\u003e / /.test(name) \u0026\u0026\n    'Name must not contain spaces'})(json) =\n{name: 'Name must not contain spaces'}\n\n// overriding default validator (string)\nerrors = validate('headmaster', 'Required')(json) =\n{headmaster: 'Required'}\n\n// overriding default validator (function)\nerrors = validate(\n  ['headmaster', 'location'],\n  (value, key) =\u003e !value \u0026\u0026 `You forgot ${_.startCase(key)}`\n)(json) =\n{headmaster: 'You forgot Headmaster', location: 'You forgot Location'}\n\n// creating new validate function\ncustomValidate = createValidate('Required')\nerrors = customValidate('headmaster')(json) =\n{headmaster: 'Required'}\n\n// deep keys\nerrors = validate('teachers[1].students[0].name')(json) =\n{teachers: {1: {students: {0: {name: 'Teachers 1 Students 0 Name is required'}}}}}\n\n// iteration (array)\nerrors = validate('teachers[]', ({name}) =\u003e !name \u0026\u0026 'Name is required')(json) =\n{teachers: {0: 'Name is required', 2: 'Name is required'}}\n\n// iteration (object)\nerrors = validate('teachers[0].students[]', ({class}) =\u003e !class \u0026\u0026 'Class is required')(json) =\n{teachers: {0: {students: {Lelouch: 'Class is required'}}}}\n\n// iteration (nested)\nerrors = validate('teachers[].students[].name', 'Required')(json) =\n{teachers: {\n  0: {students: {Lelouch: {name: 'Required'}, Suzaku: {name: 'Required'}}},\n  1: {students: {0: {name: 'Required'}}}}}\n\n/*\nWhen chaining the first error encountered (on left) takes precedence if multiple\nerrors exist for one path, every validator is always executed regardless of whether\nan error was already encountered, this is true for sync \u0026 async validators\n*/\n\n// chaining\nerrors = validate('name', 'Name required').then('location', 'Location required')(json) =\n{name: 'Name required', location: 'Location required'}\n\n// nesting validators (array)\nerrors = validate({teachers: ['0.name', '1.name']}, 'Required')(json) =\n{teachers: {0: {name: 'Required'}}}\n\n// nesting validators (object)\nerrors = validate({teachers: {'0.students': {Suzaku: '[]', Lelouch: '[]'}}}, 'Required')(json) =\n{teachers: {0: {students: {Lelouch: {name: 'Required', class: 'Required'}, Suzaku: {name: 'Required'}}}}}\n\n// nesting validators (validators)\nerrors = validate({'teachers.0': validate('name').then('students.Suzaku.name')})(json) =\n{teachers: {0: {name: 'Name is required', {students: {Suzaku: {name: 'Students Suzaku Name is required'}}}}}}\n\n// returning objects\nerrors = validate(\n  'teachers.2',\n  ({name, students}) =\u003e ({\n    name: !name \u0026\u0026 'Required',\n    students: !students.length \u0026\u0026 'Required'\n  })\n)(json) =\n{teachers: {2: {name: 'Required', students: 'Required'}}}\n\n// manipulating keys (additive)\nerrors = validate(\n  'teachers[].students\u003c._error\u003e',\n  students =\u003e !Object.keys(students).length \u0026\u0026 'At least one student required'\n)(json) =\n{teachers: {2: {students: {_error: 'At least one student required'}}}}\n\n// manipulating keys (subtractive)\nerrors = validate(\n  'teachers[]{.students}',\n  students =\u003e !Object.keys(students).length \u0026\u0026 'At least one student required'\n)(json) =\n{teachers: {2: 'At least one student required'}}\n\n// top-level keys\nerrors = validate('[]')(json) =\n{headmaster: 'Headmaster is required', location: 'Location is required'}\n\n// recursive validation\nerrors = validate(null, 'Required')(json) =\n{\n  headmaster: 'Required',\n  location: 'Required',\n  teachers: [\n    {name: 'Required', students: {\n      Lelouch: {name: 'Required', class: 'Required'},\n      Suzaku: {name: 'Required'}}},\n    {students: {\n      0: {name: 'Required', class: 'Required'}}},\n    {name: 'Required'}\n  ]\n}\n\n/*\nIf a validator mixes sync \u0026 async functions (via \"then\" or different keys)\nthe result will be an async validator\n*/\n\n// async (function)\nerrors = validate(({name}) =\u003e Promise.reject({name: `Name must be unique, ${name} already exists`}))(json) =\nPromise.reject({name: 'Name must be unique, Ashford Academy already exists'})\n\n// async (object)\nerrors = validate({name: name =\u003e Promise.reject(`Name must be unique, ${name} already exists`)})(json) =\nPromise.reject({name: 'Name must be unique, Ashford Academy already exists'})\n\n// propTypes\nimport {PropTypes} from 'react'\nerrors = validate('teachers[]', PropTypes.shape({\n  name: PropTypes.string,\n  students: PropTypes.array}))(json) =\n{teachers: {0: 'Invalid prop `teachers.0.students` of type `object` supplied to `redux-validate`, expected `array`.'}}\n```\n\n## License\n\nISC\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fashtonsix%2Fredux-validate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fashtonsix%2Fredux-validate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fashtonsix%2Fredux-validate/lists"}