Imaginați-vă că aveți un site de comerț electronic și permiteți utilizatorilor să creeze conturi folosind numele și e-mailul lor. Vrei să te asiguri că se înscriu cu nume reale, nu ceva de genul cool_dud3.

Acolo folosim validarea pentru a valida intrările și pentru a ne asigura că datele de intrare respectă anumite reguli.

Pe piață, avem deja o grămadă de biblioteci de validare, dar voi compara două biblioteci importante de validare: Joi și expres-validator pentru aplicații bazate pe express.js.

Această comparație este utilă atunci când ați decis să utilizați biblioteca externă de validare a intrărilor pentru aplicația dvs. construită expressjs și nu sunt oarecum siguri pe care să le folosiți.

Cine este ce?

Joi

Joi vă permite să creați planuri sau scheme pentru a asigura obiectele JavaScript (un obiect care stochează informații) validare de informații cheie.

Validator expres

expres-validator este un set de express.js middlewares care împachetează validator.js funcții de validare și dezinfectare.

Deci, prin definiție, putem spune că:

  • Joi poate fi utilizat pentru crearea de scheme (la fel cum folosim mongoose pentru crearea de scheme NoSQL) și îl puteți folosi cu obiecte Javascript simple. Este ca o bibliotecă plug n play și este ușor de utilizat.
  • Pe de altă parte, expres-validator utilizări validator.js pentru a valida traseele expressjs și este construit în principal pentru aplicațiile express.js. Acest lucru face ca această bibliotecă să fie mai de nișă și oferă validare personalizată și igienizare personalizată. De asemenea, mi se pare ușor de înțeles personal 🙂

Prea multe metode și API-uri pentru a face anumite validări în Joi vă pot face să vă simțiți copleșiți, astfel încât s-ar putea să ajungeți să închideți fila.

Dar s-ar putea să mă înșel – așa că să păstrăm opiniile deoparte și să comparăm ambele biblioteci.

Instanțierea

Joi

În Joi, trebuie să folosești Joi.object() pentru a crea un obiect schema Joi cu care să lucrați.

Toate schemele necesită Joi.object()pentru a procesa validarea și alte caracteristici Joi.

Trebuie să citiți separat req.body , req.params , req.query pentru a solicita corp, params și interogare.

const Joi = require('joi');

const schema = Joi.object().keys({
   // validate fields here
})

Validator expres

Puteți cere doar expres-validator și începeți să folosiți metodele sale. Nu trebuie să citiți valori din req.body , req.params , și req.query separat.

Trebuie doar să utilizați param, query, body metodele de mai jos pentru a valida intrările, respectiv, după cum puteți vedea aici:

const {
  param, query, cookies, header 
  body, validationResult } = require('express-validator/check')

app.post('/user', [   
    
// validate fields here
 
], (req, res) => {
const errors = validationResult(req);
   
  if (!errors.isEmpty()) {     
    return res.status(422).json({ errors: errors.array() });   
  }
}

Câmpul este obligatoriu

Să luăm un exemplu foarte de bază în care vrem să ne asigurăm că a username ar trebui să fie necesară string si este alphaNumeric cu min și max personaje.

  • Joi:
const Joi = require('joi');
const schema = Joi.object().keys({
    username: Joi.string().alphanum().min(3).max(30).required()
})

app.post('/user', (req, res, next) => {   
  const result = Joi.validate(req.body, schema)
  if (result.error) {
    return res.status(400).json({ error: result.error });
  }
});
  • Validator expres
const { body, validationResult } = require('express-validator/check')

app.post('/user', [   
 body('username')
  .isString()
  .isAlphanumeric()
  .isLength({min: 3, max: 30})
  .exists(), 
], (req, res) => {
  const errors = validationResult(req);
   
  if (!errors.isEmpty()) {     
    return res.status(422).json({ errors: errors.array() });   
  }
}

Igienizare

Igienizarea este practic verificarea intrării pentru a vă asigura că nu conține zgomot, de exemplu, pe care le-am folosit cu toții .trim() pe șir pentru a elimina spațiile.

Sau dacă v-ați confruntat cu o situație în care un număr vine ca. "1" deci, în aceste cazuri, vrem să igienizăm și să convertim tipul în timpul rulării.

Din păcate, Joi nu oferă igienizare din cutie, dar expres-validator face.

Exemplu: convertirea la ObjectID a MongoDB

const { sanitizeParam } = require('express-validator/filter');  

app.post('/object/:id',  
   sanitizeParam('id')
  .customSanitizer(value => {
     return ObjectId(value); 
}), (req, res) => {   // Handle the request });

Validare personalizată

Joi: .extinde(extension)

Aceasta creează o nouă instanță Joi personalizată cu extensiile pe care le furnizați incluse.

Extensia folosește câteva structuri comune care trebuie descrise mai întâi:

  • value – valoarea procesată de Joi.
  • state – un obiect care conține contextul actual de validare.
  • key – cheia valorii curente.
  • path – calea completă a valorii curente.
  • parent – părintele potențial al valorii actuale.
  • options – obiect opțiuni furnizat prin any().options() sau Joi.validate().

Extensie

extension poate fi:

  • un singur obiect de extensie
  • o funcție din fabrică care generează un obiect de extensie
  • sau o serie de acestea

Obiectele de extensie utilizează următorii parametri:

  • name – numele noului tip pe care îl definiți, acesta poate fi un tip existent. Necesar.
  • base – o schemă Joi existentă pe care să vă bazați tipul. Implicit la Joi.any().
  • coerce – o funcție opțională care rulează înainte de bază, de obicei servește atunci când doriți să constrângeți valori de un alt tip decât baza dvs. Este nevoie de 3 argumente value, state și options.
  • pre – o funcție opțională care rulează mai întâi în lanțul de validare, de obicei servește atunci când trebuie să aruncați valori. Este nevoie de 3 argumente value, state și options.
  • language – un obiect opțional pentru a adăuga definiții de eroare. Fiecare cheie va fi prefixată de numele tipului.
  • describe – o funcție opțională care ia descrierea complet formată pentru post-procesare.
  • rules – o serie opțională de reguli de adăugat.
  • name – numele noii reguli. Necesar.
  • params – un obiect opțional care conține scheme Joi ale fiecărui parametru comandat. Puteți trece, de asemenea, o singură schemă Joi atâta timp cât este Joi.object(). Desigur, unele metode, cum ar fi pattern sau rename nu va fi util sau nu va funcționa deloc în acest context dat.
  • setup – o funcție opțională care ia un obiect cu parametrii furnizați pentru a permite manipularea internă a schemei atunci când este setată o regulă. Opțional, puteți returna o nouă schemă Joi care va fi luată ca nouă instanță de schemă. Cel puțin una dintre ele setup sau validate trebuie furnizate.
  • validate – o funcție opțională pentru validarea valorilor care ia 4 parametri params, value, state și options. Cel puțin unul dintre setup sau validate trebuie furnizate.
  • description – un șir sau o funcție opțională care ia parametrii ca argument pentru a descrie ceea ce face regula.

Exemplu:

joi.extend((joi) => ({
    base: joi.object().keys({
        name: joi.string(),
        age: joi.number(),
        adult: joi.bool().optional(),
    }),
    name: 'person',
    language: {
        adult: 'needs to be an adult',
    },
rules: [
        {
            name: 'adult',
            validate(params, value, state, options) {

                if (!value.adult) {
                    // Generate an error, state and options need to be passed
                    return this.createError('person.adult', {}, state, options);
                }

                return value; // Everything is OK
            }
        }
    ]
})

Validator expres

Un validator personalizat poate fi implementat utilizând metoda lanțului .custom(). Este nevoie de o funcție de validare.

Validatorii personalizați pot returna Promisiunile de a indica o validare asincronă (care va fi așteptată) sau throw orice valoare / respinge o promisiune de a utilizați un mesaj de eroare personalizat.

const {
  param, query, cookies, header 
  body, validationResult } = require('express-validator/check')

app.get('/user/:userId', [   
 param('userId')
  .exists()
  .isMongoId()
  .custom(val => UserSchema.isValidUser(val)), 
], (req, res) => {
    
const errors = validationResult(req);
   
  if (!errors.isEmpty()) {     
    return res.status(422).json({ errors: errors.array() });   
  }
}

Validare condiționată

expres-validator nu acceptă validarea condiționată de acum, dar există un PR pentru asta, pe care îl puteți verifica deja https://github.com/express-validator/express-validator/pull/658

Să vedem cum funcționează în Joi:

any.when(condition, options)

any: Generează un obiect schemă care se potrivește cu orice tip de date.

const schema = Joi.object({
    a: Joi.any().valid('x'),
    b: Joi.any()
}).when(
    Joi.object({ b: Joi.exist() })
    .unknown(), {
    then: Joi.object({
        a: Joi.valid('y')
    }),
    otherwise: Joi.object({
        a: Joi.valid('z')
    })
});

alternatives.when(condition, options)

Adaugă un tip de schemă alternativă condiționată, fie pe baza unei alte chei (nu la fel ca any.when()) sau o schemă care se uită la valoarea curentă, unde:

  • condition – numele cheii sau referinţă, sau o schemă.
  • options – un obiect cu:
  • is – starea necesară tip joi. Interzis când condition este o schemă.
  • then – tipul de schemă alternativă pentru a încerca dacă condiția este adevărată. Obligatoriu dacă otherwise lipseste.
  • otherwise – tipul de schemă alternativă pentru a încerca dacă condiția este falsă. Obligatoriu dacă then lipseste.
const schema = Joi
     .alternatives()
     .when(Joi.object({ b: 5 }).unknown(), {
        then: Joi.object({
           a: Joi.string(),
           b: Joi.any()
      }),
      otherwise: Joi.object({
        a: Joi.number(),
        b: Joi.any()
      })
});

Validare imbricată

Când doriți să validați o serie de obiecte / articole sau doar chei de obiecte

Ambele biblioteci acceptă validarea imbricată

Acum ce zici de validator expres?

Wildcards

Comercierii vă permit să repetați o serie de articole sau chei de obiecte și să validați fiecare articol sau proprietățile sale.

* caracterul este, de asemenea, cunoscut sub numele de wildcard.

const express = require('express'); 
const { check } = require('express-validator/check'); 
const { sanitize } = require('express-validator/filter');  
const app = express(); 

app.use(express.json());  
app.post('/addresses', [   
    check('addresses.*.postalCode').isPostalCode(),
    sanitize('addresses.*.number').toInt() 
], 
(req, res) => {   // Handle the request });

Joi

const schema = Joi.object().keys({
    addresses: Joi.array().items(
        Joi.object().keys({
            postalCode: Joi.string().required(),
        }),
    )
});

Mesaje de eroare personalizate

Joi

any.error(err, [options])

Înlocuiește eroarea joi implicită cu o eroare personalizată

let schema = Joi.string().error(new Error('Was REALLY expecting a string'));

Validator expres

const { check } = require('express-validator/check'); 

app.post('/user', [   
   // ...some other validations...   
   check('password')     
   .isLength({ min: 5 }).withMessage('must be at 5 chars long')
   .matches(/d/).withMessage('must contain a number') 
], 
(req, res) => {   // Handle the request somehow });

Concluzie

Am acoperit cele mai importante părți ale ambelor biblioteci și vă puteți decide singur pe care doriți să îl utilizați. Vă rog să-mi spuneți în comentariile de mai jos dacă am lăsat deoparte ceva important în comparație.

Sper să vă fie de ajutor atunci când decideți următorul modul de validare a intrării pentru aplicația dvs. express.js.

Am scris aici un articol detaliat: cum se validează intrările. Verifică-l.

Nu ezitați să bateți din palme dacă ați considerat că este o lectură utilă!

Publicat inițial la 101node.io pe 31 martie 2019.