Tartalomjegyzék

< Érvényesség ES

Express - Sequelize beépített érvényesítés ES

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:

employee.js
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:

employeecontroller.js
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:

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