Skip to content

Repository files navigation

Validasaur

tagCILicense: MITtagnest badge

Validasaur is Deno validation library slightly inspired by Laravel Validation.

Table of Contents

Examples

Basic Usage

Write your example.ts like this:

import{validate,required,isNumber}from"https://deno.land/x/validasaur/mod.ts";constinputs={name: "",age: "20"};const[passes,errors]=awaitvalidate(inputs,{name: required,age: [required,isNumber]});console.log({ passes, errors });

Run code above with:

deno run example.ts

And this is the result:

{
"passes": false,
"errors": {
"name": {
"required": "name is required"
},
"age": {
"isNumber": "age must be a number"
}
}
}

Formatting Errors

If you want a simpler error message, you can use flattenMessages or firstMessages to format error messages.

For example:

import{validate,flattenMessages,firstMessages,required,isNumber}from"https://deno.land/x/validasaur/mod.ts";constinputs={name: "",age: "20"};const[passes,errors]=awaitvalidate(inputs,{name: required,age: [required,isNumber]});constfirstErrors=firstMessages(errors);constflattenErrors=flattenMessages(errors);// Show the differenceconsole.log({defaultErrors: errors,
firstErrors,
flattenErrors
});

Result:

{
"defaultErrors": {
"name": {
"required": "name is required"
},
"age": {
"isNumber": "age must be a number"
}
},
"firstErrors": {
"name": "name is required",
"age": "age must be a number"
},
"flattenErrors": {
"name.required": "name is required",
"age.isNumber": "age must be a number",
"name": "name is required",
"age": "age must be a number"
}
}

Custom Error Message

import{validate,InvalidParams,required,isNumber,isIn,isString,}from"https://deno.land/x/validasaur/mod.ts";constinputs={name: "",age: "12",sex: "unknown",};const[passes,errors]=awaitvalidate(inputs,{name: required,age: [required,isNumber],sex: [required,isString,isIn(["male","female"])]},{messages: {"name": "Nama tidak boleh kosong","age.required": "Usia tidak boleh kosong","age.isNumber": "Usia harus berupa angka",// Using function"isIn": (params: InvalidParams): string=>{constallowedValues=params.allowedValues.join("/");return`${params.attr} field doesn't allow '${params.value}', it only allows ${allowedValues}`;},// Use this if you want same message for any rule fail// "age": "Usia tidak valid",},});console.log({ passes, errors });

Result:

{
"passes": false,
"errors": {
"name": {
"required": "Nama tidak boleh kosong"
},
"age": {
"isNumber": "Usia harus berupa angka"
}
}
}

Validating Array and Object

import{validate,flattenMessages,required,isNumber,isString,validateArray,validateObject}from"https://deno.land/x/validasaur/mod.ts";constinputs={name: "",age: "20",skills: ["PHP","Node.js",0,"Deno"],address: {street: null,city: "Jakarta",country: "Indonesia",}};const[passes,errors]=awaitvalidate(inputs,{name: required,age: [required,isNumber],// validateArray(required: boolean, rules: Rule[])skills: validateArray(true,[isString]),// validateObject(required: boolean, rules: ValidationRule)address: validateObject(true,{street: required,city: required,country: required,}),});constflattenErrors=flattenMessages(errors);console.log({ passes, flattenErrors });

Result:

{
"passes": false,
"flattenErrors": {
"name.required": "name is required",
"age.isNumber": "age must be a number",
"skills.2.isString": "2 must be a string",
"address.street.required": "street is required",
"name": "name is required",
"age": "age must be a number",
"skills.2": "2 must be a string",
"address.street": "street is required"
}
}

Make Your own Simple Rule Validation

In this example we will make an isOdd rule validation that check odd number.

First, let's make is_odd.ts like this:

import{invalid,Validity}from"https://deno.land/x/validasaur/mod.ts";exportfunctionisOdd(value: any): Validity{if(typeofvalue!=="number"){returninvalid("isOdd",{ value });}if(value%2!==1){returninvalid("isOdd",{ value });}}

Now, we can use it like this:

import{validate,flattenMessages,firstMessages,required,isNumber}from"https://deno.land/x/validasaur/mod.ts";import{isOdd}from"./is_odd.ts";constinputs={number: 20};const[passes,errors]=awaitvalidate(inputs,{number: [required,isNumber,isOdd]});console.log({ passes, errors });

Make More Advanced Rule Validation

In this example we will make a unique rule that check value availability in the database. This rule accepts table and column as arguments, then calling database function to check availability based on those arguments.

First, let's make our unique.ts:

importdbfrom"./your_db_service.ts";import{invalid,Validity,Rule}from"https://deno.land/x/validasaur/mod.ts";exportfunctionunique(table: string,column: string): Rule{returnasyncfunctionuniqueRule(value: any): Promise<Validity>{if(typeofvalue!=="string"&&typeofvalue!=="number"){returninvalid("unique",{ value, table, column });}constdata=awaitdb.findOne(table,{[column]: value});if(data!==null){returninvalid("unique",{ value, table, column });}};}

Now we can use it like this:

import{validate,flattenMessages,firstMessages,required,isEmail}from"https://deno.land/x/validasaur/mod.ts";import{unique}from"./unique.ts";constinputs={email: "emsifa@gmail.com"};const[passes,errors]=awaitvalidate(inputs,{email: [required,isEmail,unique("users","email")]});console.log({ passes, errors });

Available Rules

required

Value under this field should not be null, undefined, or an empty string ("").

  • Invalid values: null, undefined, ""
  • Valid values: "0", [], {}, 0, etc.

When you don't put required on a field, that field will be considered as optional field. Which means when it's value is undefined, null, or "", that field will be considered as valid without checking for next rules.

either(ruleSets: (Rule|Rule[])[], errorCode: string = 'either')

Use this as an OR operator.

For example you may want to accept ipv4 or ipv6, you can use either rule like below:

Example:

const[passes,errors]=awaitvalidate({value1: "1.2.3.4",value2: "::1",value3: "not an IP address"},{value1: [required,either([isIPv4,isIPv6])],// validvalue2: [required,either([isIPv4,isIPv6])],// validvalue3: [required,either([isIPv4,isIPv6])],// invalid})

You may want define errorCode to use appropriate custom message:

const[passes,errors]=awaitvalidate({value: "foobarbaz"},{value: [required,either([isIPv4,isIPv6],"ipAddress")],},{messages: {"ipAddress": ":attr is not valid IP address"}})

endsWith(str: string)

Value under this field must be a string that ends with given str.

Example:

const[passes,errors]=awaitvalidate({value1: null,value2: "barfoo",value3: "foobar"},{value1: endsWith("bar"),// invalidvalue2: endsWith("bar"),// invalidvalue3: endsWith("bar"),// valid})

isArray

Value under this field must be an array.

  • Invalid values: "", 10, 0.5, etc.
  • Valid values: [], [1, 2, 3], [{x: 10}, {x: 12}], etc.

isBool

Value under this field must be a boolean.

  • Invalid values: "", 10, 0.5, etc.
  • Valid values: true and false.

isDate

Value under this field must be a string that has length >= 10 and can be parsed by Date.parse().

  • Invalid values: 2020, "01-2020-10", "2020-01", etc.
  • Valid values: "2020-01-02", "2020-01-02 10:20:30", "2020/01/02", etc.

isEmail

Value under this field must be valid email address.

  • Invalid values: "someone name", 123, foo.bar.baz, foo@bar@baz, etc.
  • Valid values: "someone@mail.com", "someone@mail.co.id", "someone@[1.2.3.4]", etc.

isFloat

Value under this field must be a float number.

  • Invalid values: "0.1", [], 0, 1, 123, etc.
  • Valid values: 0.1, 1.2, 12.345, etc.

isIn(allowedValues: PrimitiveTypes[])

Value under this field must be one of allowed values.

Example:

const[passes,errors]=awaitvalidate({value1: "yes",value2: "no",value3: "maybe"},{value1: isIn(["yes","no"]),// passesvalue2: isIn(["yes","no"]),// passesvalue3: isIn(["yes","no"]),// fail})

isInt

Value under this field must be an integer.

  • Invalid values: 0.5, "123", etc.
  • Valid values: 0, 123, etc.

isIPv4

Value under this field must be valid IPv4.

  • Invalid values: "foo", "a.b.c.d", "1.2.3.256", "1.02.3.4", etc.
  • Valid values: "0.0.0.0", "1.2.3.4", "255.255.255.255", etc.

isIPv6

Value under this field must be valid IPv6.

  • Invalid values: "2001:af40:::", "2001:af40:::1234", "2001::af40::1234", "1080:0:0:0:8:800:200C:417G", etc.
  • Valid values: "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210", "::1:2:3:4:5:6:7", "::1", "::", etc.

isNumber

Value under this field must be a float or an integer.

  • Invalid values: "1", "1.5", etc.
  • Valid values: 1, 1.5, etc.

isNumeric

Same as asNumber, but it allows numeric string.

  • Invalid values: "1.0abc", "x.1", etc.
  • Valid values: 1, 1.5, "2", "2.5", etc.

isString

Value under this field must be a string.

  • Invalid values: 1, 1.5, etc.
  • Valid values: "1", "1.5", "foo", etc.

lengthBetween(minLength: number, maxLength: number)

Value under this field must be a string that has char length between minLength and maxLength.

Example:

const[passes,errors]=awaitvalidate({value1: 'foo',value2: 'foobar',value3: 'fo',value4: 'foobars',},{value1: lengthBetween(3,6),// passesvalue2: lengthBetween(3,6),// passesvalue3: lengthBetween(3,6),// failvalue4: lengthBetween(3,6),// fail})

match(regex: RegExp, trim: boolean = false)

Value under this field must be a string that match with given regex.

const[passes,errors]=awaitvalidate({value1: 'foo$',value2: '$foo',value3: 'foo1',value4: 'foo2',value5: ' foo3',value6: ' foo4',},{value1: match(/^[a-z0-9]{4}$/),// failvalue2: match(/^[a-z0-9]{4}$/),// failvalue3: match(/^[a-z0-9]{4}$/),// passesvalue4: match(/^[a-z0-9]{4}$/),// passesvalue5: match(/^[a-z0-9]{4}$/),// failvalue6: match(/^[a-z0-9]{4}$/,true),// passes after trim})

maxLength(minValue: number)

Value under this field must be a string that has char length lower or equals maxValue.

Example:

const[passes,errors]=awaitvalidate({value1: 'foobarbaz',value2: 'foobar',},{value1: maxLength(6),// failvalue2: maxLength(6),// passes})

maxNumber(maxValue: number)

Value under this field should be a number that is not higher than maxValue.

Example:

const[passes,errors]=awaitvalidate({value1: 6,value2: 5.01,value3: 5,value4: 4},{value1: maxNumber(5),// failvalue2: maxNumber(5),// failvalue3: maxNumber(5),// passesvalue4: maxNumber(5),// passes})

minLength(minValue: number)

Value under this field must be a string that has char length higher or equals minValue.

Example:

const[passes,errors]=awaitvalidate({value1: 'foo',value2: 'foobar',},{value1: minLength(6),// failvalue2: minLength(6),// passes})

minNumber(minValue: number)

Value under this field should be a number that is not lower than minValue.

Example:

const[passes,errors]=awaitvalidate({value1: 1,value2: 4.99,value3: 5,value4: 5.01,},{value1: minNumber(5),// failvalue2: minNumber(5),// failvalue3: minNumber(5),// passesvalue4: minNumber(5),// passes})

notIn(disallowedValues: PrimitiveTypes[])

Value under this field must not be one of disallowed values.

Example:

const[passes,errors]=awaitvalidate({value1: "yes",value2: "no",value3: "maybe"},{value1: notIn(["yes","no"]),// failvalue2: notIn(["yes","no"]),// failvalue3: notIn(["yes","no"]),// passes})

notNull

Value under this field must not be null.

nullable

In case you need a required field that accept null value, you can put nullable after required field. So when the value is null, validator will consider your value as valid without checking for next rules.

Example:

const[passes,errors]=awaitvalidate({value1: null,value2: null,value3: "3",value4: 4,},{value1: [required,isNumber],// failed on requiredvalue2: [required,nullable,isNumber],// passesvalue3: [required,nullable,isNumber],// failed on isNumbervalue4: [required,nullable,isNumber],// passes})

numberBetween(minValue: number, maxValue: number)

Value under this field must be a number between minValue and maxValue.

const[passes,errors]=awaitvalidate({value1: 5,value2: 10,value3: 4.99,value4: 10.01,},{value1: numberBetween(5,10),// passesvalue2: numberBetween(5,10),// passesvalue3: numberBetween(5,10),// failvalue4: numberBetween(5,10),// fail})

requiredIf(field: string, fieldValue: any)

Field within this rule will be required if given field match fieldValue.

const[passes,errors]=awaitvalidate({value1: null,value2: "2",value3: null,otherField: 1,},{value1: [requiredIf('otherField',1),isNumber],// failed at requiredvalue2: [requiredIf('otherField',1),isNumber],// failed at isNumbervalue3: [requiredIf('otherField',0),isNumber],// passes because value3 becomes optional})

requiredUnless(field: string, fieldValue: any)

Field within this rule will be required if given field doesn't match with fieldValue.

const[passes,errors]=awaitvalidate({value1: null,value2: "2",value3: null,otherField: 1,},{value1: [requiredUnless('otherField',9),isNumber],// failed at requiredvalue2: [requiredUnless('otherField',6),isNumber],// failed at isNumbervalue3: [requiredUnless('otherField',1),isNumber],// passes because value3 becomes optional})

requiredWhen(callback: (value: any, utils: ValidationUtils) => boolean|Promise<boolean>)

Field within this rule will be required if callback returns true.

const[passes,errors]=awaitvalidate({value1: null,value2: "2",value3: null,value4: null,otherField: 10,},{value1: [requiredWhen(()=>true),isNumber],// failed at requiredvalue2: [requiredWhen(()=>true),isNumber],// failed at isNumbervalue3: [requiredWhen(()=>false),isNumber],// passes because value3 becomes optionalvalue4: [requiredWhen((_,{ getValue }): boolean=>{constx=getValue('otherField');returntypeofx!=="number"||x%2===0;}),isNumber],// this will fail because value4 is null and otherField|x is 10 where 10 % 2 === 0})

startsWith(str: string)

Value under this field must be a string that starts with given str.

Example:

const[passes,errors]=awaitvalidate({value1: null,value2: "barfoo",value3: "foobar"},{value1: startsWith("foo"),// invalidvalue2: startsWith("foo"),// invalidvalue3: startsWith("foo"),// valid})

Contributing

All contributions are welcome, make sure to read the contribution guideline.

About

Deno validation library

Resources

Code of conduct

Contributing

Stars

46 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages