Kako odabrati koji validator koristiti: usporedba Joi-a i express-validatora

Zamislite da imate web mjesto za e-trgovinu i dopuštate korisnicima da stvaraju račune koristeći svoje ime i e-poštu. Želite biti sigurni da su se prijavili pravim imenima, a ne nečim poput cool_dud3.

Tu koristimo provjeru valjanosti za provjeru ulaznih podataka i provjeru slijede li ulazni podaci određena pravila.

Na tržištu već imamo hrpu knjižnica za provjeru valjanosti, ali usporedit ću dvije važne knjižnice za provjeru valjanosti: Joi i express-validator za aplikacije temeljene na express.js .

Ova je usporedba korisna kada ste odlučili koristiti vanjsku knjižnicu za provjeru unosa za svoju aplikaciju izgrađenu na expressjs-u i pomalo niste sigurni koju biste koristili.

Tko je što?

Joi

Joi vam omogućuje stvaranje nacrta ili shema za JavaScript objekte (objekt koji pohranjuje informacije) kako bi se osigurala provjera valjanosti ključnih podataka.

Express-validator

express-validator je skup express.js posredničkih programa koji objedinjuje validator.js funkcije provjere i dezinfekcije.

Prema definiciji, možemo reći da:

  • Joi se može koristiti za stvaranje shema (baš kao što mi koristimo mongoose za stvaranje NoSQL shema), a možete ga koristiti s običnim Javascript objektima. To je poput plug n play biblioteke i jednostavan je za upotrebu.
  • S druge strane, express-validator koristi validator.js za provjeru valjanosti expressjs ruta i uglavnom je napravljen za express.js aplikacije. To ovu knjižnicu čini nišom i nudi prilagođenu provjeru valjanosti i sanaciju. Također, smatram da je to osobno lako razumjeti :)

Previše metoda i API-ja za obavljanje određene provjere valjanosti u Joiu može vas natjerati da se osjećate preplavljeno pa biste na kraju zatvorili karticu.

Ali možda griješim - zato ostavimo mišljenja po strani i usporedimo obje knjižnice.

Instanciranje

Joi

UJoi , trebaš koristitiJoi.object()instancirati objekt sheme Joi za rad.

Sve sheme zahtijevaju Joi.object()obradu provjere valjanosti i ostalih Joi značajki.

Morate se zasebno čitati req.body, req.params, req.queryna tijelu zahtjev, parametre koji te upita.

const Joi = require('joi'); const schema = Joi.object().keys({ // validate fields here })

Express-validator

Možete samo zatražiti ekspresni validator ipočnite koristiti njegove metode. Ne morate čitati vrijednosti iz req.body, req.paramsi req.queryodvojeno.

Samo trebate koristiti param, query, bodydonje metode za provjeru unosa, kao što ovdje možete vidjeti:

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() }); } }

Polje je obavezno

Uzmimo vrlo osnovni primjer gdje želimo biti sigurni da usernametreba biti potrebno stringi da li je alphaNumerics mini maxznakovima.

  • 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 }); } });
  • Express-validator
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() }); } }

Sanitizacija

Sanitization je u osnovi provjera unosa kako bi se osiguralo da nema buke, na primjer, svi smo koristili .trim()string kako bismo uklonili razmake.

Ili ako ste se suočili sa situacijom u kojoj dolazi broj, kao "1"i u tim slučajevima, želimo sanirati i pretvoriti vrstu tijekom izvođenja.

Nažalost, Joi ne vrši sanaciju iz kutije, ali Express-validator to čini.

Primjer: pretvaranje u MongoDB-ov ObjectID

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

Prilagođena provjera valjanosti

Joi: .extend ( extension)

Ovo stvara novu instancu Joi prilagođenu uključenim proširenjima koja pružate.

Proširenje koristi neke uobičajene strukture koje treba prvo opisati:

  • value - vrijednost koju obrađuje Joi.
  • state - objekt koji sadrži trenutni kontekst provjere valjanosti.
  • key - ključ trenutne vrijednosti.
  • path - puni put trenutne vrijednosti.
  • parent - potencijalni roditelj trenutne vrijednosti.
  • options- opcija objekta koja se pruža putem any().options()ili Joi.validate().

Proširenje

extension Može biti:

  • jedan produžni objekt
  • tvornička funkcija koja generira ekstenzijski objekt
  • ili niz takvih

Objekti ekstenzije koriste sljedeće parametre:

  • name- naziv novog tipa koji definirate, ovo može biti postojeći tip. Potreban.
  • base- postojeća Joi shema na kojoj se temelji vaš tip. Zadane vrijednosti Joi.any().
  • coerce- neobavezna funkcija koja se izvodi prije baze, obično služi kada želite prisiliti vrijednosti drugog tipa od vaše baze. To traje 3 argumente value, statea options.
  • pre- neobavezna funkcija koja se prva pokreće u lancu provjere valjanosti, obično služi kada trebate emitirati vrijednosti. To traje 3 argumente value, statea options.
  • language- neobavezni objekt za dodavanje definicija pogrešaka. Svaki tip ima prefiks imena tipa.
  • describe - neobavezna funkcija koja uzima potpuno oblikovani opis da bi ga naknadno obradila.
  • rules - neobavezan niz pravila za dodavanje.
  • name- naziv novog pravila. Potreban.
  • params- neobavezni objekt koji sadrži Joi sheme svakog naručenog parametra. Također možete proslijediti jednu Joi shemu ako je to Joi.object(). Naravno, neke metode poput patternili renameneće biti korisne ili uopće neće raditi u ovom zadanom kontekstu.
  • setup- neobavezna funkcija koja uzima objekt s navedenim parametrima kako bi omogućila unutarnju manipulaciju shemom kada je postavljeno pravilo. Po želji možete vratiti novu Joi shemu koja će se uzeti kao nova instanca sheme. Barem jedan od bilo kojeg setupili validatemora biti osiguran.
  • validate- dodatna funkcija za provjeru valjanosti vrijednosti koje traje 4 parametre params, value, statei options. Barem jedan setupili validatemora biti osiguran.
  • description - neobavezni niz ili funkcija koji uzimaju parametre kao argument za opisivanje pravila.

Primjer :

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 } } ] })

Express-validator

Prilagođeni validator može se implementirati pomoću lančane metode .custom(). Potrebna je funkcija validatora.

Prilagođeni validatori mogu vratiti Obećanja kako bi ukazali na asinkronizaciju (na koju će se čekati) ili throwbilo koju vrijednost / odbiti obećanje da će koristiti prilagođenu poruku o pogrešci.

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() }); } }

Uvjetna provjera valjanosti

express-validator does not support conditional validation as of now, but there is a PR for that already you can check //github.com/express-validator/express-validator/pull/658

Let’s see how it works in Joi:

any.when(condition, options)

any:Generates a schema object that matches any data type.

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)

Adds a conditional alternative schema type, either based on another key (not the same as any.when()) value, or a schema peeking into the current value, where:

  • condition - the key name or reference, or a schema.
  • options - an object with:
  • is - the required condition joi type. Forbidden when condition is a schema.
  • then - the alternative schema type to try if the condition is true. Required if otherwise is missing.
  • otherwise - the alternative schema type to try if the condition is false. Required if then is missing.
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() }) });

Nested Validation

When you want to validate an array of objects/items or just object keys

Both libraries support nested validation

Now what about express-validator?

Wildcards

Wildcards allow you to iterate over an array of items or object keys and validate each item or its properties.

The * character is also known as a 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(), }), ) });

Custom Error Messages

Joi

any.error(err, [options])

Overrides the default joi error with a custom error

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

Express-validator

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 });

Conclusion

I covered the most important parts of both libraries and you can decide yourself which one you want to use. Please let me know in the comments below if I left out anything important in the comparison.

I hope you find it helpful when deciding the next input validation module for your express.js application.

I wrote an in-depth article on it here: how to validate inputs. Do check it out.

Don’t hesitate to clap if you considered this a worthwhile read!

Originally published at 101node.io on March 31, 2019.