{"id":13551198,"url":"https://github.com/DanielCardonaRojas/verify","last_synced_at":"2025-04-03T01:31:35.308Z","repository":{"id":49223552,"uuid":"247788841","full_name":"DanielCardonaRojas/verify","owner":"DanielCardonaRojas","description":"A Dart validation DSL to validate your flutter app models.","archived":false,"fork":false,"pushed_at":"2023-10-11T16:32:57.000Z","size":206,"stargazers_count":28,"open_issues_count":1,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-26T20:49:54.477Z","etag":null,"topics":["dart","dartlang","flutter","input-validation","validation"],"latest_commit_sha":null,"homepage":null,"language":"Dart","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/DanielCardonaRojas.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","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":"2020-03-16T18:28:20.000Z","updated_at":"2023-10-11T04:58:05.000Z","dependencies_parsed_at":"2023-10-11T01:07:24.540Z","dependency_job_id":"76c55f47-ac58-45fd-a88f-acabfacb87db","html_url":"https://github.com/DanielCardonaRojas/verify","commit_stats":{"total_commits":37,"total_committers":3,"mean_commits":"12.333333333333334","dds":0.08108108108108103,"last_synced_commit":"a4f5afc261cbc728d3b360e4f3e9b3f271112fd6"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DanielCardonaRojas%2Fverify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DanielCardonaRojas%2Fverify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DanielCardonaRojas%2Fverify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DanielCardonaRojas%2Fverify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DanielCardonaRojas","download_url":"https://codeload.github.com/DanielCardonaRojas/verify/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246922091,"owners_count":20855341,"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":["dart","dartlang","flutter","input-validation","validation"],"created_at":"2024-08-01T12:01:44.028Z","updated_at":"2025-04-03T01:31:34.809Z","avatar_url":"https://github.com/DanielCardonaRojas.png","language":"Dart","readme":"\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://github.com/DanielCardonaRojas/verify/raw/master/verify_logo.png\" height=\"250px\"\u003e\n\u003c/p\u003e\n\n\u003ch2 align=\"center\"\u003e\n  Validations made simple\n\u003c/h2\u003e\n\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://travis-ci.org/github/DanielCardonaRojas/verify\"\u003e\n\u003cimg alt=\"Build Status\" src=\"https://travis-ci.org/DanielCardonaRojas/verify.svg?branch=master\"\u003e\n\u003c/a\u003e\n \u003ca href=\"https://pub.dartlang.org/packages/verify\"\u003e\n    \u003cimg alt=\"Pub Package\" src=\"https://img.shields.io/pub/v/verify.svg\"\u003e\n  \u003c/a\u003e\n\n  \u003ca href=\"https://codecov.io/gh/DanielCardonaRojas/verify\"\u003e\n    \u003cimg alt=\"Codecov\" src=\"https://codecov.io/gh/DanielCardonaRojas/verify/branch/master/graph/badge.svg\"\u003e\n  \u003c/a\u003e\n\n\u003ca href=\"https://opensource.org/licenses/MIT\"\u003e\n\u003cimg alt=\"MIT License\" src=\"https://img.shields.io/badge/License-MIT-blue.svg\"\u003e\n\u003c/a\u003e\n\n\u003c/p\u003e\n\nA fp inspired validation DSL. For Dart and Flutter projects.\n\n## Features\n\n- Completely extensible (create your own combinators, validator primitives, etc)\n- Flexible Verify is an extension based API (There is not single class created its all pure functions)\n- Customizable (Define you own error types if required) organize validators how ever you want\n- Bloc friendly (See [examples](https://github.com/DanielCardonaRojas/verify/tree/master/example) for a concrete implementation)\n- Null safe (as a prerelease)\n\n## Usage\n\n### Creating validators\n\nA Validator is just a simple function alias:\n\n```dart\n// One of 2 variats depending on wether the validated subject will be transformed into another type or not\ntypedef ValidatorT\u003cS, T\u003e = Either\u003cList\u003cdynamic\u003e, T\u003e Function(S subject);\ntypedef Validator\u003cS\u003e = Either\u003cList\u003cdynamic\u003e, S\u003e Function(S subject);\n```\n\nSo you can create your own validator by just specifying a function for example:\n\n```dart\nfinal Validator\u003cString\u003e emailValidator = (String email) {\n  return email.contains('@') ? Right(email) : Left('Bad email format')\n};\n```\n\n**Create simple validators from predicates**\n\nA simpler way is to use some of the built in helpers.\n\n```dart\nfinal contains@ = Verify.that(\n  (String email) =\u003e email.contains('@'),\n    error: 'Bad email format'\n    );\n\n```\n\nUse custom errors and filter them by type\n\n### Reuse validators\n\nUse composition to build up more complex validators.\n\n```dart\nfinal Validator\u003cString\u003e emailValidator = Verify.all([ contains@, notEmpty ])\n```\n\n### Validate and transform\n\nValidators are also capable of transforming their input, so for instance we can do\nparsing and validation in one go.\n\n```dart\nfinal Validator\u003cString, int\u003e intParsingValidator = (String str) =\u003e Right(int.parse(str));\n\nfinal validator = intParsingValidator.onException((_) =\u003e Error('not an integer'));\n```\n\n### Field validations\n\nGiven a model, for instance a user:\n\n```dart\nclass User extends Equatable {\n  final String? phone;\n  final String? mail;\n  final int? age;\n\n  const User(this.phone, this.mail, this.age);\n\n  @override\n  List\u003cObject\u003e get props =\u003e [phone ?? '', mail ?? '', age ?? ''];\n}\n```\n\nAdditional checks can be performed on the object and its fields by chaining a series of `check`\nand `checkField` methods.\n\n```dart\nfinal userValidator = Verify.empty\u003cUser\u003e()\n    .check((user) =\u003e !user.phone!.isEmpty, error: Error('phone empty'))\n    .checkField((user) =\u003e user.mail!, emailValidator);\n\nfinal someUser = User('','', 25);\nfinal Either\u003cList\u003cError\u003e, User\u003e validationResult = userValidator.verify(someUser);\n```\n\n\u003e Note: The difference between check and checkField is that the later ignore the verification when the value is null,\n\u003e this will likely change in next version supporting null safety.\n\n### Run a validator\n\nRunning a validator is a simple as passing in a parameter since its just a function.\nTo be a bit more eloquent a `verify` method is provided, this method is special because besides\nforwarding the argument to the calling validator it can also be used to filter the error list and\nhave it cast to a specific error type. Just supply a specific type parameter.\n\n```dart\nfinal signUpValidation = Verify.subject\u003cSignUpState\u003e();\nfinal errors = signUpValidation\n    .verify\u003cSignUpError\u003e(newState); // Either\u003cList\u003cSignUpError\u003e, SignUpState\u003e\n```\n\n### Built in validators\n\nVerify doesn't come with many built in validators, because they are so simple to create.\n\nIt does come with some regex shorthands.\n\n```dart\nfinal validator = Verify.fromRegex(RegExp(r\"(^\\d+$)\", error: Error('not just digits')) // Validator\u003cString, int\u003e\n```\n\n### Form validation\n\nOften times you will have modeled your error type similar to:\n\n```dart\nenum FormField {\n  email,\n  password,\n  passwordConfirmation,\n}\n\nclass SignUpError extends ValidationError {\n  final String message;\n  final FormField field;\n\n  SignUpError(this.message, {required this.field});\n\n  @override\n  String get errorDescription =\u003e message;\n}\n```\n\nIn these scenarios its convenient to be able to group errors by field.\n\nThe solution verify provides for this is:\n\n```dart\nfinal validator = Verify.inOrder\u003cSignUpFormState\u003e([\n  validateMail,\n  validatePassword,\n  validateConfirmation,\n]);\n\nfinal Map\u003cFormField, SignUpError\u003e errorMap = validator\n    .verify\u003cSignUpError\u003e(someState)\n    .errorsGroupedBy((error) =\u003e error.field);\n```\n\n## Sequencing\n\nA slightly different API can be used to achieve the same results as the `inOrder` composition function.\n\n```dart\nfinal numberValidator = Verify.subject\u003cint\u003e()\n  .then(Verify.that(\n    (subject) =\u003e subject % 2 == 0,\n    error: Error('not even'),\n  ))\n  .then(Verify.that(\n    (subject) =\u003e subject \u003e= 10,\n    error: Error('single digit'),\n  ));\n\nfinal errors2 = numberValidator.errors(3); // yields 1 error\nfinal errors = numberValidator.errors(4); // yields 1 error\n```\n\nThis way you have quick access to errors segmented by field.\n","funding_links":[],"categories":["Dart"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDanielCardonaRojas%2Fverify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FDanielCardonaRojas%2Fverify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDanielCardonaRojas%2Fverify/lists"}