[[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