[[oktatas:web:back-end_framework:express:ervenyesseg_es|< Érvényesség ES]] ====== Express - Sequelize beépített érvényesítés ES ====== * **Szerző:** Sallai András * Copyright (c) 2025, Sallai András * Licenc: [[https://creativecommons.org/licenses/by-sa/4.0/|CC BY-SA 4.0]] * Web: https://szit.hu ===== Bevezetés ===== Az Sequelize rendelkezik beépített érvényesség-ellenőrzéssel. Itt a Sequelize 6.x verzióhoz tartozó érvényességvizsgálatot nézzük át. ===== Model ===== Egy Employee model minimális id és name mezővel: const Employee = sequelize.define('employee', { id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true }, name: { type: DataTypes.STRING, allowNull: false } }) Az "allowNull: false" azt határozza meg, hogy az adatbázisban a tábla mezője lehet null érték. Ha viszont érvényességet szeretnénk vizsgálni, akár hibaüzenettel a valaidate: {} kulcsot kell használni. Az érvényesség vizsgálat során a HTTP kérésben érkező kérésben szereplő adatokat vizsgáljuk. A validate: {} értékén belül objektumokat vehetünk fel, vagyis újabb kulcs-éréték párok. Ilyen például, a **notNull** a body-ban érkező adatokra vonatkozik. A **notEmpty** azért kellhet, mert a notNull esetén még küldhető üres sztring. A notEmpty esetén nem. Nézzük meg **name** mező érvényességvizsgálatát. const Employee = sequelize.define('employee', { id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true }, name: { type: DataTypes.STRING, allowNull: false, validate: { notNull: true notEmpty: true } } }) A true helyett megadhatunk JavaScript objektumként üzenet is: const Employee = sequelize.define('employee', { id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true }, name: { type: DataTypes.STRING, allowNull: false, validate: { notNull: { msg: 'A név mező kötelező' }, notEmpty: { msg: 'A név nem lehet üres sztring' } } } }) A validate: { notNull: true } csak a allowNull: false mellett használható. A validate: { notEmpty: true } önmagában megengedi, hogy ne adjuk meg az adott mezőt, de ha megadjuk nem lehet üres sztring, például "". Lássunk egy összetettebb kódot, ahol már több mező is szerepel, szabályos kifejezéssel is: import { DataTypes } from 'sequelize' import sequelize from '../database/database.js' const Employee = sequelize.define('employee', { id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true }, name: { type: DataTypes.STRING, allowNull: false, validate: { notNull: { msg: 'Hiba! A név megadása kötelező!' }, notEmpty: { msg: 'Hiba! A név nem lehet üres!'} } }, city: { type: DataTypes.STRING, allowNull: true, validate: { is: { args: /^[a-z]+$/i, msg: 'Hiba! Csak betűk adhatók meg!' } } }, salary: { type: DataTypes.INTEGER, defaultValue: 300, validate: { isNumeric: { msg: 'Hiba! Csak szám adható meg fizetésnek!'} } }, birth: { type: DataTypes.DATE, defaultValue: DataTypes.NOW, validate: { isDate: { msg: 'Hiba! Csak dátum adható meg!' } } } }) sequelize.sync({ force: false }) export default Employee ===== Kontroller ===== Az érvényességet a modell-ben beállítottuk. Most nézzük egy példát, hogyan kezelhetjük az érvénytelen eseteket. A hibakezelő részben vizsgáljuk meg, hogy érvényességi hiba történt-e: if(error instanceof Sequelize.ValidationError) { res.status(400) }else { res.status(500) } Megvizsgáljuk, hogy az error objektum a Sequelize.ValidationError egy példánya? Ha igen, akkor a kérés a hibás, ezért 400-as státuszkódot állítunk. Ha nem az érvényesség volt a hiba, akkor valószínűleg szerver oldali hiba, ezért a státuszkód 500 lesz. Lehetséges teljes kód: import { Sequelize } from 'sequelize' import Employee from '../models/employee.js' const EmployeeController = { async index(req, res) { try { await EmployeeController.tryIndex(req, res) }catch(error) { res.status(500) res.json({ success: false, message: 'Error! The query is failed!', error: error.message }) } }, async tryIndex(req, res) { const employees = await Employee.findAll() const result = employees.map(emp => ({ id: emp.id, name: emp.name, city: emp.city, salary: emp.salary, birth: emp.birth })) res.status(200) res.json({ success: true, data: result }) }, async show(req, res) { try { await EmployeeController.tryShow(req, res) }catch(error) { res.status(500) res.json({ success: false, message: 'Error! The query is failed!' }) } }, async tryShow(req, res) { const employee = await Employee.findByPk(req.params.id) res.status(200) res.json({ success: true, data: employee }) }, async create(req, res) { try { await EmployeeController.tryCreate(req, res) }catch(error) { if(error instanceof Sequelize.ValidationError) { res.status(400) }else { res.status(500) } const errorMessages = error.errors.map(err => err.message) res.json({ success: false, message: 'Error! The query is failed!', error: errorMessages }) } }, async tryCreate(req, res) { const employee = await Employee.create(req.body) res.status(201) res.json({ success: true, data: employee }) }, async update(req, res) { try { await EmployeeController.tryUpdate(req, res) }catch(error) { let actualMessage = ''; if(error.message == 'Fail! Record not found!') { actualMessage = error.message res.status(404) }else { res.status(500) actualMessage = 'Fail! The query is failed!' } res.json({ success: false, message: actualMessage }) } }, async tryUpdate(req, res) { const recordNumber = await Employee.update(req.body, { where: { id: req.params.id } }) if(recordNumber == 0) { throw new Error('Fail! Record not found!') } const employee = await Employee.findByPk(req.params.id) res.status(200) res.json({ success: true, data: employee }) }, async destroy(req, res) { try { await EmployeeController.tryDestroy(req, res) }catch(error) { res.status(500) res.json({ success: false, message: 'Error! The query is failed!' }) } }, async tryDestroy(req, res) { const employee = await Employee.destroy({ where: { id: req.params.id } }) res.status(200) res.json({ success: true, data: employee }) } } export default EmployeeController A mintaprogramban a hibakezelés és a lényegi kód szét van választva, ezért látunk név függvényt: * index() * tryIndex() * store() * tryStore() Ha szeretnénk látni az modellben megadott egyedi hibaüzenetet a try..catch szerkezetbe: error: error.message Például: try { await EmployeeController.tryCreate(req, res) }catch(error) { res.status(500) res.json({ success: false, message: 'Error! The query is failed!', error: error.message }) } Egy másik lehetőség: const errorMessages = error.errors.map(err => err.message) //... error: errorMessges ===== Beépített érvényesítők ===== A következő kódrészlet a Sequelize 6 verziójának beépített érvényesítőit mutatja: sequelize.define('foo', { bar: { type: DataTypes.STRING, validate: { is: /^[a-z]+$/i, // RegEx egyezés is: ["^[a-z]+$",'i'], // Mint a fenti, csak a RegEx karakterláncból áll not: /^[a-z]+$/i, // RegEx nem egyezés not: ["^[a-z]+$",'i'], // Mint a fenti, csak a RegEx karakterláncból áll isEmail: true, // email cím (foo@bar.com) isUrl: true, // URL elfogadása (https://foo.com) isIP: true, // IPv4 (129.89.23.1) vagy IPv6 formátum isIPv4: true, // IPv4 (129.89.23.1) cím isIPv6: true, // IPv6 cím isAlpha: true, // csak betűk az elfogadottak isAlphanumeric: true, // betűk és számok; ez nem érvényes: "_abc" isNumeric: true, // csak szám isInt: true, // csak egész isFloat: true, // csak valós szám isDecimal: true, // csak szám isLowercase: true, // csak kisbetűs isUppercase: true, // csak nagybetűs notNull: true, // a null nem megengedett isNull: true, // csak null a megengedett notEmpty: true, // nem lehet üres sztirng equals: 'specific value', // csak a megadott érték lehet contains: 'foo', // benne kell legyen ez a sztring rész notIn: [['foo', 'bar']], // ezek az értékek nem lehetnek isIn: [['foo', 'bar']], // csak ezek az értékek lehetnek notContains: 'bar', // csak ha nem tartalmazza ezt rész sztringet len: [2,10], // az érték hossza 2 és 10 között lehet isUUID: 4, // csak uuid a megengedett isDate: true, // csak dátum sztring lehet isAfter: "2025-04-23", // csak az adott dátum után dátum isBefore: "2025-04-23", // csak az adott dátum előtt dátum max: 23, // az érték <= 23 min: 23, // az érétk >= 23 isCreditCard: true, // csak valós credit card számok } } }); ===== Saját érvényesítő ===== Készítünk egy érvényesítőt isAfterOrEqualToday néven, amihez egy névtelen függvényt rendelünk: const YourModel = sequelize.define('YourModel', { // ... egyéb mezők ... startDate: { type: DataTypes.DATE, allowNull: true, validate: { isDate: true, isAfterOrEqualToday: function(value) { const today = new Date(); today.setHours(0, 0, 0, 0); // Mai nap éjfélkor const startDate = new Date(value); startDate.setHours(0, 0, 0, 0); if (isNaN(startDate.getTime()) || startDate < today) { throw new Error('A kezdő dátum nem lehet korábbi a mai napnál.'); } }, }, }, // ... egyéb mezők ... }); Ha nem érvényes a dátum, akkor kivételt dobunk. ===== Lásd még ===== * https://sequelize.org/docs/v6/core-concepts/validations-and-constraints/ * https://sequelize.org/docs/v7/models/validations-and-constraints/ * https://github.com/validatorjs/validator.js