:white_check_mark: Easy property validation for JavaScript, Node and Express.

Overview

property-validator

Build Status

โœ… Easy property validation for JavaScript, Node and Express

Built on top of validator.js, property-validator makes validating request parameters easy and fun. No chaining, no prototype violations, no magic. Just some simple, stateless, javascript functions.

All you have to do is import some base validation functions and declare the validation rules for your request.

Table of contents

Installation

npm install --save property-validator

Usage

property-validator provides a suite of validate and assert functions to make request validation simple and easy to write.

assert functions halt the programs's execution if one of the validation rules breaks.

import { assert, presence, email } from 'property-validator';

let user = {
  username: 'nettofarah',
  email_address: 'invalid@email'
}

assert(user, [
  presence('username'),
  email('email_address')
]);

// will throw a ValidationError

// /Users/netto/projects/property-validator/lib/request_assertions.js:8
//    throw new ValidationError(validation);

validate functions on the other hand, will return an object containing the result of all validations.

import { validate, presence, email } from 'property-validator';

let user = {
  username: 'nettofarah',
  email_address: 'invalid@email'
}

validate(user, [
  presence('username'),
  email('email_address')
]);

// returns
{
  valid: false,
  errors :[
    {
      field: "email_address",
      message: "\"email_address\" should look like an email address"
    }
  ],
  messages: [
    "\"email_address\" should look like an email address"
  ]
}

property-validator really shines when you combine it with web servers.

Usage in NodeJS

You can run validations and assertions against the request body, query, params and headers, or against all of them at once using assertAll or validateAll.

Using assertAll:

import express from 'express';
import { assertAll, presence, email, assertMiddleware } from 'property-validator';

const app = express();

app.get('/hello', function(req, res){
  assertAll(req, [
    presence('username'),
    email('email_address')
  ]);

  res.status(200).json({ name: req.query.username });
});

app.use(assertMiddleware);

Request Validation

property-validator offers out of the box support for request params, query string, body and header validations.

All you have to do is to import the correct function and annotate your request handler.

Request Parameters

You can run validations against incoming request params.

import { validateParams, presence } from 'property-validator';

app.get('/hello/:username', function(req, res){
  const validation = validateParams(req, [
    presence('username')
  ]);

  if (validation.valid) {
    res.status(200).json({ name: req.query.username });
  } else {
    res.status(422).json({ errors: validation.errors });
  }
});

or use the assertParams counterpart:

import { assertParams, presence } from 'property-validator';

app.get('/hello/:username', function(req, res){
  assertParams(req, [
    presence('username')
  ]);

  // No need to check the validation result
  res.status(200).json({ name: req.query.username });
});

Query String

import { validateQuery, email } from 'property-validator';

app.get('/hi', function(req, res){
  const validation = validateQuery(req, [
    email('primary_email_address')
  ]);

  if (validation.valid) {
    res.status(200).send('We promise not to send spam!');
  } else {
    res.status(422).json({ errors: validation.errors });
  }
});

or use the assertQuery counterpart:

import { assertQuery, email } from 'property-validator';

app.get('/hi', function(req, res){
  assertQuery(req, [
    email('primary_email_address')
  ]);

  // No need to check the validation result
  res.status(200).send('We promise not to send spam!');
});

Body

import { validateBody, presence, email } from 'property-validator';

app.post('/sign-up', function(req, res){
  const validation = validateBody(req, [
    email('user.email'),
    presence('user.password'),
    presence('user.password_confirmation')
  ]);

  if (validation.valid) {
    res.status(200).send('Welcome!');
  } else {
    res.status(422).send({ errors: validation.errors });
  }
});

or use the assertBody counterpart:

import { assertBody, presence, email } from 'property-validator';

app.post('/sign-up', function(req, res){
  assertBody(req, [
    email('user.email'),
    presence('user.password'),
    presence('user.password_confirmation')
  ]);

  // No need to check the validation result
  res.status(200).send('Welcome!');
});

Headers

import { validateHeaders, presence, format } from 'property-validator';

app.get('/secret-stuff', function(req, res){
  const validation = validateHeaders(req, [
    presence('Authorization'),
    format('Authorization', /Token token="\w+"/)
  ]);

  if (validation.valid) {
    res.status(200).send('Here is all your secret stuff!');
  } else {
    res.status(401).send('You shall not pass!');
  }
});

or use the assertHeaders counterpart:

import { assertHeaders, presence, format } from 'property-validator';

app.get('/secret-stuff', function(req, res){
  assertHeaders(req, [
    presence('Authorization'),
    format('Authorization', /Token token="\w+"/)
  ]);

  // No need to check the validation result
  res.status(200).send('Here is all your secret stuff!');
});

Everything

You can use validateAll or assertAll to run validation rules against all properties at once (body, params, query). Important: validateAll and assertAll will not run validations agains headers since they're pretty different use cases.

Assert Middleware

property-validator ships with a standard middleware that automatically handles assert errors. All you have to do is to import assertMiddleware and mount it after all request handlers in your express app.

import express from 'express';
import { assertAll, presence, email, assertMiddleware } from 'property-validator';

const app = express();

app.get('/hello', function(req, res){
  assertAll(req, [
    presence('username'),
    email('email_address')
  ]);

  res.status(200).json({ name: req.query.username });
});

app.post('/bla', ...);
...

app.get('/test', ...);

app.use(assertMiddleware);

You can also roll your own middleware in case you need any sort of customization.

import { ValidationError } from 'property-validator';

app.use(function(err, req, res, next) {
  // Do not swallow all kinds of errors
  const isValidationError = (err instanceof ValidationError);
  if (!isValidationError) {
    return next(err);
  }

  const messages = err.messages;
  res.status(422);

  res.json({
    notice: "Your request is invalid",
    errors: messages
  })
});

Advanced usage

property-validator is extensible. You can set optional property validation, customize your custom messages and write your own validation functions.

Optional Validation

optional is a special validation helper that can be used when fields are not strictly required, but need to be validated in case they are present.

You can pass in any other validation helper, and propery-validator will only run the helper function against the input params if the optional field is present.

Pagination is usually a good use case for optional params:

var validation = validate(params, [
  optional(isNumeric('limit')),
  optional(isNumeric('offset'))
]);

Custom Error Messages

Validation helpers allow custom messages to be set. You can set the validation message to any string you want.

All you need to do is to pass in a custom error message as the last param when calling any validation helper.

var validation = validate(params, [
  presence('name', 'Oops, you forgot to tell us your name'),
  isCurrency('rent_in_brl', { symbol: 'R$' }, 'Reais should be prefixed with R$'),
  isCurrency('rent', 'This does not look like money')
]);

It is also possible to use some of the parameters of your validator in the error message.

var validation = validate(params, [
  presence('name', 'Oops, you forgot to tell us your :paramName'),
  isLength('value', { min: 10, max: 99 }, 'The :paramName should be between :min and :max')
]);

//Oops, you forgot to tell us your name
//The value should be between 10 and 99

Custom localization

It is possible to override the default locals. The locals is a simple object with keys refering to a validation function and there value the message.

import { assert, presence, isLength, email, setLocals } from 'property-validator';
setLocals({
  required: 'Oops, you forgot to tell us your :paramName'
});

var validation = validate(params, [
  presence('name'),
  isLength('value', { min: 10, max: 99 }, 'The :paramName should be between :min and :max'),
  email('email')
]);

//Oops, you forgot to tell us your name
//The value should be between 10 and 99
//"email" should look like an email address

As you can see all kind of combinations are possible. You can override the default locals and still set a custom message. And if you neither supply a translation through the setLocals nor set a custom message, it will fall back to the default locals.

If you would like to restore the locals to the default locals simply call restoreDefaultLocals like so:

import { restoreDefaultLocals } from 'property-validator';

restoreDefaultLocals();

Custom Validation Functions

Writing your own validation functions is easy.

// Your function will receive a property name as its argument
function isTheUltimateAnswer(propertyName) {
  // and then return a function that takes the
  // actual object you want to validate
  return function(subject) {
    var value = subject[propertyName]
    var isAnswer = value === 42

    // Make sure your function returns `result`, `message`
    // and `field`
    return {
      result: isAnswer,
      message: value + " is not the Answer to the Ultimate Question of Life, The Universe, and Everything",
      field: propertyName
    }
  }
}

You can now use your custom function as you would with any other validation helper:

var subject = {
  'guess': 43
}

var validation = validate(subject, [
  isTheUltimateAnswer('guess')
]);

Validation Helpers

Validation helpers are functions you can use to validate incoming request properties.

property-validator relies on the super battle tested validator.js library.

Supported Helpers

Here's a list of currently supported helpers:

Helper Description
presence(paramName) check if the current param is present.
optional(validationHelper(paramName, ...)) takes in another validation helper and only runs the validation if the optional field is present.
oneOf(paramName, optionList) checks if the input param is one of the values within a list of valid options.
contains(paramName, seed) check if the string contains the seed.
equals(paramName, comparison) check if the string matches the comparison.
isAlpha(paramName) check if the string contains only letters (a-zA-Z).
isAlphanumeric(paramName) check if the string contains only letters and numbers.
isArray(paramName) check if the current param is an array.
isCreditCard(paramName) check if the string is a credit card.
isCurrency(paramName, options) check if the string is a valid currency amount. options is an object which defaults to {symbol: '$', require_symbol: false, allow_space_after_symbol: false, symbol_after_digits: false, allow_negatives: true, parens_for_negatives: false, negative_sign_before_digits: false, negative_sign_after_digits: false, allow_negative_sign_placeholder: false, thousands_separator: ',', decimal_separator: '.', allow_space_after_digits: false }.
isDate(paramName) check if the string is a date.
isDecimal(paramName) check if the string represents a decimal number, such as 0.1, .3, 1.1, 1.00003, 4.0, etc.
isEmail(paramName [, options]) check if the string is an email. options is an object which defaults to { allow_display_name: false, allow_utf8_local_part: true, require_tld: true }. If allow_display_name is set to true, the validator will also match Display Name <email-address>. If allow_utf8_local_part is set to false, the validator will not allow any non-English UTF8 character in email address' local part. If require_tld is set to false, e-mail addresses without having TLD in their domain will also be matched.
isIn(paramName, values) check if the string is in a array of allowed values.
isInt(paramName [, options]) check if the string is an integer. options is an object which can contain the keys min and/or max to check the integer is within boundaries (e.g. { min: 10, max: 99 }).
isJSON(paramName) check if the string is valid JSON (note: uses JSON.parse).
isNull(paramName) check if the string is null.
isNumeric(paramName) check if the string contains only numbers.
isURL(paramName [, options]) check if the string is an URL. options is an object which defaults to { protocols: ['http','https','ftp'], require_tld: true, require_protocol: false, require_valid_protocol: true, allow_underscores: false, host_whitelist: false, host_blacklist: false, allow_trailing_dot: false, allow_protocol_relative_urls: false }.
isUUID(paramName [, version]) check if the string is a UUID (version 3, 4 or 5).
matches(paramName, pattern [, modifiers]) check if string matches the pattern. Either matches('foo', /foo/i) or matches('foo', 'foo', 'i').
isPlainObject(paramName) check if the current param is a plain object.
isLength(paramName, options) check if the string's length falls in a range. Note: this function takes into account surrogate pairs. options is an object which can contain the keys min and/or max to check the integer is within boundaries (e.g. { min: 10, max: 99 }).

Not currently supported

These are a few other helpers avaliable in validator.js that could be used in property-validator. Feel free to submit a PR if you need any of these functions.

Helper Description
isAfter(paramName [, date]) check if the string is a date that's after the specified date (defaults to now).
isAscii(paramName) check if the string contains ASCII chars only.
isBase64(paramName) check if a string is base64 encoded.
isBefore(paramName [, date]) check if the string is a date that's before the specified date.
isBoolean(paramName) check if a string is a boolean.
isByteLength(paramName, min [, max]) check if the string's length (in bytes) falls in a range.
isDivisibleBy(paramName, number) check if the string is a number that's divisible by another.
isFQDN(paramName [, options]) check if the string is a fully qualified domain name (e.g. domain.com). options is an object which defaults to { require_tld: true, allow_underscores: false, allow_trailing_dot: false }.
isFloat(paramName [, options]) check if the string is a float. options is an object which can contain the keys min and/or max to validate the float is within boundaries (e.g. { min: 7.22, max: 9.55 }).
isFullWidth(paramName) check if the string contains any full-width chars.
isHalfWidth(paramName) check if the string contains any half-width chars.
isHexColor(paramName) check if the string is a hexadecimal color.
isHexadecimal(paramName) check if the string is a hexadecimal number.
isIP(paramName [, version]) check if the string is an IP (version 4 or 6).
isISBN(paramName [, version]) check if the string is an ISBN (version 10 or 13).
isISIN(paramName) check if the string is an [ISIN][ISIN] (stock/security identifier).
isISO8601(paramName) check if the string is a valid ISO 8601 date.
isLowercase(paramName) check if the string is lowercase.
isMACAddress(paramName) check if the string is a MAC address.
isMobilePhone(paramName, locale) check if the string is a mobile phone number, (locale is one of ['zh-CN', 'zh-TW', 'en-ZA', 'en-AU', 'en-HK', 'pt-PT', 'fr-FR', 'el-GR', 'en-GB', 'en-US', 'en-ZM', 'ru-RU', 'nb-NO', 'nn-NO', 'vi-VN', 'en-NZ', 'en-IN']).
isMongoId(paramName) check if the string is a valid hex-encoded representation of a [MongoDB ObjectId][mongoid].
isMultibyte(paramName) check if the string contains one or more multibyte chars.
isSurrogatePair(paramName) check if the string contains any surrogate pairs chars.
isUppercase(paramName) check if the string is uppercase.
isVariableWidth(paramName) check if the string contains a mixture of full and half-width chars.
isWhitelisted(paramName, chars) checks characters if they appear in the whitelist.

Usage with TypeScript

There is no need to install additional type definitions for property-validator since it ships with TypeScript definition files.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/nettofarah/property-validator. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Code of Conduct.

To run the specs check out the repo and follow these steps:

$ npm install
$ npm run test

License

The module is available as open source under the terms of the MIT License.

Comments
  • Added typescript typings in index.d.ts.

    Added typescript typings in index.d.ts.

    I am using property-validator in a typescript codebase so I had to make some typings. Guess it would be usefull for some other people hence this pull request.

    Let me know what you think and if we want this ๐Ÿ˜„

    opened by DJWassink 10
  • Added translation support

    Added translation support

    Hey guys a few days ago I added support for translation and have been running it locally here for a while and it works quite okay.

    The api is pretty simple and I will give a example with the email validator. As you can see on line 56 of validations.js https://github.com/nettofarah/property-validator/compare/master...change/localization#diff-6fb54c87831f7e0eeab9cbbbc5b2b9feR56 the code looks like this:

    translator(customMessage || 'email', {paramName: paramName}, locals)
    

    the translator takes a message, which is either a customMessage or a name pointing to a translation. If this name (in this case 'email') is present in the translation JSON its will replace the customMessage.

    Without a customMessage it will take the string on: https://github.com/nettofarah/property-validator/compare/master...change/localization#diff-f06d6e49f5230c6ec1d195c064770b81R3 And the translator will try to fill the message with properties of the second argument of the translator function in the translation string, so in the email string : 'The ":paramName" must be a valid email address', :paramName will be replace with the paramName variable. (see the second argument in the aboven snippet {paramName: paramName})

    For users the default error string is already quite usable but it they want they are able to supply there own customMessage and choose themself if they use the custom properties or not.

    opened by DJWassink 7
  • Should allow label options also.

    Should allow label options also.

    if i do presence('first_name') in req.body and if first_name is not present then the validation message that is returned is first_name required better option is to allow one more parameter called label and to generate the validation message, label should be used like presence(param,label) so in this case i can presence('first_name','First Name') so the validation message generated for this field would be First Name is required and this message could be directly shown to user in front end.

    opened by delveintechnolabs 5
  • isPlainObject/isArray validation

    isPlainObject/isArray validation

    hi! i need to validate some optional fields that i don't know its shape so these validations would be really useful.

    validateBody(req, [
      optional(isPlainObject('customFields'))
      optional(isArray('customValues'))
    ]);
    
    // because the fields are optional..
    if (!req.body.customFields || !req.body.customValues) {
      return res.status(400).json({ message: 'some message' });
    }
    
    // need to be able to use Object.keys(), Array.forEach with confidence here
    
    // app logic
    Object.keys(req.body.customFields).forEach(function() {
    
    });
    
    req.body.customValues.forEach(function() {
    
    });
    
    opened by bjrmatos 3
  • Update package.json to include index.d.ts

    Update package.json to include index.d.ts

    ๐Ÿคฆโ€โ™‚๏ธ when I developed the types I had them locally installed and never tested them with the NPM version, because it simply worked..

    Would be nice if we could merge this ASAP and publish 0.8.1 so that types also get installed through npm

    opened by DJWassink 1
  • Validation for mongoose record is present or not

    Validation for mongoose record is present or not

    Hi, I'm trying to write a custom validation, if a mongoose Record is present or not. If the record is not present throw validation error. Here is the code assertAll(req, [presence('mongooseId'), validateRecordId('mongooseId')]);

    here validateFleetGroup is the custom function, which is defined as:

    let validateRecordId = (propertyName) => {
        return async function (subject) {
            let value = subject[propertyName];
            await mongooseDb.findOne({
                _id: mongoose.Types.ObjectId(value)
            }, (findError, data) => {
                if (findError) {
                    // Make sure your function returns `result`, `message`
                    // and `field`
                    return {
                        result: false,
                        message: "Record Not Found",
                        field: propertyName
                    }
                } else {
                    return {
                        result: true,
                        message: "Record Found",
                        field: propertyName
                    }
                }
            });
        }
    }
    

    Can any one please help me what i am doing wrong?

    opened by srinivasaltair 1
  • Fixed a bug in the typescript definition and updated readme.

    Fixed a bug in the typescript definition and updated readme.

    Buch of small different changes in this PR.

    I am not completely sure about including the @types/validator package with property-validator. It is required that it is preset in the dependencies instead of devDependencies because of: https://github.com/Microsoft/types-publisher/issues/81

    Instead of this we could change the readme to tell users to install this package manually if they wan't the correct typings.

    But I guess most users use it at the backend so this package isn't that much of a burden. And frontend devs properly don't even include the definitions anyway. Anyhow let me know what you think.

    opened by DJWassink 0
  • Custom messages

    Custom messages

    Some big changes here. This will allow developers to provide custom error messages (in case the default error messages don't work for your use case).

    closes #5.

    opened by nettofarah 0
  • Optional validation

    Optional validation

    property-validator now supports optional as a validation helper. We can now use optional every time a field is not required, but needs to be validated in case it is present.

    opened by nettofarah 0
  • `isDate` is no longer supported

    `isDate` is no longer supported

    https://github.com/nettofarah/property-validator/blob/f0c8e31f5d68470cb7c2a1020bca4601dd71375a/lib/validations.js#L221

    https://github.com/validatorjs/validator.js/issues/1130

    opened by mshwery 0
  • Help required in understanding validation function

    Help required in understanding validation function

    Hi,

    I am using your Library for one of my project, Its a great library. i have been playing around the code for developing a async validations. I am stuck in a part of your code. I would be glad if u can help me understand. here is a snippet of the code where a little knowledge is required.```

        validations.presence = function presence(paramName, customMessage) {
          return function(params) {
    
            return {
              field: paramName,
              message: translator(customMessage || 'required', {paramName: paramName}, locals),
              result: get(params, paramName) != null
           }
         }
       }
    

    I want to know how the params value is passed?

    Thank you.

    opened by WaseemAR 2
  • Sanitize option for some validators

    Sanitize option for some validators

    Hi! do you will accept a PR that implements a sanitize: true option? for example for isDate, isDecimal , isInt validations would be nice to have a sanitize option to automatically convert the value if is valid.

    isInt('paramName', { sanitize: true })

    what do you think?

    opened by bjrmatos 7
Releases(v1.0.2)
Owner
Netto Farah
Software Engineer @segmentio. formerly @IFTTT, @8tracks and @thoughtworks
Netto Farah
FieldVal - multipurpose validation library. Supports both sync and async validation.

FieldVal-JS The FieldVal-JS library allows you to easily validate data and provide readable and structured error reports. Documentation and Examples D

null 137 Sep 24, 2022
Lightweight JavaScript form validation library inspired by CodeIgniter.

validate.js validate.js is a lightweight JavaScript form validation library inspired by CodeIgniter. Features Validate form fields from over a dozen r

Rick Harrison 2.6k Dec 15, 2022
A simple credit cards validation library in JavaScript

creditcard.js A simple credit cards validation library in JavaScript. Project website: https://contaazul.github.io/creditcard.js Install creditcard.js

ContaAzul 323 Jan 7, 2023
v8n โ˜‘๏ธ ultimate JavaScript validation library

The ultimate JavaScript validation library you've ever needed. Dead simple fluent API. Customizable. Reusable. Installation - Documentation - API Intr

Bruno C. Couto 4.1k Dec 30, 2022
Schema-Inspector is an JSON API sanitisation and validation module.

Schema-Inspector is a powerful tool to sanitize and validate JS objects. It's designed to work both client-side and server-side and to be scalable wit

null 494 Oct 3, 2022
Lightweight and powerfull library for declarative form validation

Formurai is a lightweight and powerfull library for declarative form validation Features Setup Usage Options Methods Rules Examples Roadmap Features ?

Illia 49 May 13, 2022
Facile is an HTML form validator that is inspired by Laravel's validation style and is designed for simplicity of use.

Facile is an HTML form validator that is inspired by Laravel's validation style and is designed for simplicity of use.

upjs 314 Dec 26, 2022
TypeScript-first schema validation for h3 and Nuxt applications

h3-zod Validate h3 and Nuxt 3 requests using zod schema's. Install npm install h3-zod Usage import { createServer } from 'http' import { createApp } f

Robert Soriano 48 Dec 28, 2022
Simple, smart and pleasant validation solution.

nice-validator Simple, smart and pleasant validation solution. Download the latest release or install package via npm or bower $ npm install nice-vali

Jony 608 Nov 18, 2022
Themis is a validation and processing library that helps you always make sure your data is correct.

Dataffy Themis - The advanced validation library Themis is a validation and processing library that helps you always make sure your data is correct. ยท

Dataffy 14 Oct 27, 2022
jQuery Validation Plugin library sources

jQuery Validation Plugin - Form validation made easy The jQuery Validation Plugin provides drop-in validation for your existing forms, while making al

null 10.3k Jan 3, 2023
String validation

validator.js A library of string validators and sanitizers. Strings only This library validates and sanitizes strings only. If you're not sure if your

null 20.7k Jan 5, 2023
Cross Browser HTML5 Form Validation.

Validatr Cross Browser HTML5 Form Validation. Getting Started View the documentation to learn how to use Validatr. Changelog Version 0.5.1 - 2013-03-1

Jay Morrow 279 Nov 1, 2022
jQuery Validation Plugin library sources

jQuery Validation Plugin - Form validation made easy The jQuery Validation Plugin provides drop-in validation for your existing forms, while making al

null 10.3k Jan 3, 2023
jQuery form validation plugin

jQuery.validationEngine v3.1.0 Looking for official contributors This project has now been going on for more than 7 years, right now I only maintain t

Cedric Dugas 2.6k Dec 23, 2022
The most powerful data validation library for JS

joi The most powerful schema description language and data validator for JavaScript. Installation npm install joi Visit the joi.dev Developer Portal f

Sideway Inc. 19.6k Jan 4, 2023
Dead simple Object schema validation

Yup Yup is a JavaScript schema builder for value parsing and validation. Define a schema, transform a value to match, validate the shape of an existin

Jason Quense 19.2k Jan 2, 2023
A lightweight NodeJS library for strict mime-type validation on streams

A lightweight NodeJS library for strict mime-type validation on streams. It gets a ReadableStream and decets the mime-type using its Magic number and validates it using the provided allowed and forbidden lists; If it's allowed it will pass it to the created WritableStreams and if it's not it will throw an error.

CEO of Death Star 9 Apr 3, 2022
๐Ÿ“ซ Offline email validation - JS or TS

email-seems-valid An offline check to see if an email seems valid. Contains TS or JS packages for browser or Node.js emailSeemsValid('[email protected]')

earnifi 12 Dec 25, 2022