[[:oktatas:web:back-end_framework:express|< Express]] ====== Express - Sequelize ====== * **Szerző:** Sallai András * Copyright (c) 2023, Sallai András * Licenc: [[https://creativecommons.org/licenses/by-sa/4.0/|CC Attribution-Share Alike 4.0 International]] * Web: https://szit.hu ===== A Sequalize ===== A Sequelize egy TypeScript és NodeJS alapú ORM a következő adatbázis rendszerek számára: * Oracle * Postres * MySQL * MariaDB * SQLite * SQL Server * stb. Webhely: * https://sequelize.org/ (2023) Példa: * https://github.com/oktat/empjs_simple Ebben a Sequelize-t a lehető legegyszerűbben használjuk. Nem használunk migrációt, feltöltőt (seeder). Migráció helyett, a modellen futtatható sync() függvényt használjuk, ami automatikusan létrehozza a modellben megadott táblát, és a későbbiekben is szinkronizálja. A táblák a szerver induláskor azonnal létrejönnek. ===== Projket ===== npm init -y npm install express ===== Projekt könyvtárszerkezet ===== empapi/ |-app/ | |-controllers/ | |-database/ | |-models/ | |-routes/ | `-indexjs |-node_modules/ |-tools/ |-.env |-.env.example |.package.json `-pnpm-lock.yaml ===== Függőségek telepítés ===== npm install sequelize mariadb sqlite3 dotenv morgan npm install --save-dev nodemon ===== Környezet ===== Feltételezzük, hogy van egy emp nevű adatbázis, egy emp nevű felhasználóval, aki a "titok" jelszóval éri el az adatbázist. A beállításokat az .env fájlban végezzük, ami alapértelmezetten a projekt gyökérkönyvtárba szokás tenni. APP_PORT=8000 DB_DIALECT=mariadb DB_HOST=127.0.0.1 DB_NAME=dbname DB_USER=dbuser DB_PASS=dbpassword DB_STORAGE=/ut/vonal A fájlról készítsünk másolatot .env néven, majd töltsük ki. APP_PORT=8000 DB_DIALECT=mariadb DB_HOST=127.0.0.1 DB_NAME=emp DB_USER=emp DB_PASS=titok DB_STORAGE=/ut/vonal A DB_DIALECT lehetséges értékei esetünkben: * mariadb * sqlite A DB_STORAGE értéke lehet: * útvonal /ut/vonal * :memory: A :memory: csak sqlite dialaktus mellett állítható be, és azt jelenti, az adatbázis a memóriában van, az alkalmazás újraindításával törlődik. ===== Adatbázis ===== MySQL vagy MariaDB adatbázisban hozzuk lére az adatbázist és a hozzátartozó felhasználót. create database emp character set utf8 collate utf8_hungarian_ci; grant all privileges on emp.* to emp@localhost identified by 'titok'; A táblák automatikusan létrejönnek a sequelize.sync() függvény hívás hatására az emplyoee.js fájlban. ===== MariaDB adatbázis elérése ===== A többféle adatbázist használunk, azt is elég egyetlen fájlban megadni. Itt most csak MariaDB adatbázist használunk, ezért a nevet is **database.js** lett. const Sequelize = require('sequelize') require('dotenv').config() const sequelize = new Sequelize( process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASS, { host: process.env.DB_HOST, dialect: process.env.DB_DIALECT, storage: process.env.DB_STORAGE, host: process.env.DB_HOST, dialectOptions: {} } ) module.exports = sequelize A process.env.DB kezdetű sorok, az adatokat a .env fájlból olvassák. ===== Model definiálása ===== const { DataTypes } = require('sequelize') const sequelize = require('../database/database') //employees nevű tábla jön létre const Employee = sequelize.define('employees', { id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true }, name: { type: DataTypes.STRING, allowNull: false }, city: { type: DataTypes.STRING, allowNull: true }, salary: { type: DataTypes.DOUBLE , defaultValue: 0 } }) //A model és az adatbázis szinkronizálása, nem erőltetve. sequelize.sync({ force: false }) module.exports = Employee A "nem erőltetve" annyit jelent, hogy új mezők létrejönnek, de meglévőket nem írja felül. Igény szerint a felülírás is kikényszeríthető a force: true értékkel. Egyéb típusok ^ Jelölés ^ Jelentés ^ | DataTypes.INTEGER | egész | | DataTypes.STRING | sztring | | DataTypes.DATE | Dátum és idő | | DataTypes.DOUBLE | Double | | DataTypes.FLOAT | Float | | DataTypes.DECIMAL | Decimális | | DataTypes.BOOLEAN | TINYINT(1) | Az itt megadott típusok nem az összes használható típus, csak néhány általánosat került ide. A következő linkeken találunk még használható típusokat: * https://sequelize.org/docs/v6/core-concepts/model-basics/ (2023) * https://sequelize.org/docs/v6/other-topics/other-data-types/ (2023) ===== Kontroller ===== Az employeecontroller.js állományban hozzuk létre az EmployeeController-t, ami négy függvényt tartalmaz: index(), store(), update() és destroy(). const Employee = require('../models/employee') const EmployeeController = { async index(req, res) { try { const emps = await Employee.findAll() res.status(200) res.json({ success: true, data: emps }) } catch (error) { res.status(500) res.send('Hiba') } }, async store(req, res) { try { const emp = await Employee.create(req.body) res.status(201) res.json({ success: true, data: emp }) } catch (error) { res.status(500) res.send('Hiba') } }, async update(req, res) { try { const id = req.params.id const emp = await Employee.update(req.body, { where: {id: id} }) res.status(200) res.json({ success: true, data: emp }) } catch (error) { res.status(500) res.send('Hiba') } }, async destroy(req, res) { try { const id = req.params.id const emp = await Employee.destroy({ where: {id: id} }) res.status(200) res.json({ success: true, data: emp }) } catch (error) { res.status(500) res.send('Hiba') } } } module.exports = EmployeeController A példában a minden függvényben try...catch szerkezetben valósítjuk meg a kérések feldolgozását és a válaszokat. Ezeket a kivételkezeléseket érdemes külön függvényekbe szerverni. ===== Routing ===== Az útválasztó rész, jelenleg négy útvonalat tartalmaz, négy különböző metódussal. Az útválasztáshoz az express útválasztó objektumát használjuk. const Router = require('express'); const router = Router(); const EmployeeController = require('../controllers/employeecontroller') router.get('/employees', EmployeeController.index) router.post('/employees', EmployeeController.store) router.put('/employees/:id', EmployeeController.update) router.delete('/employees/:id', EmployeeController.destroy) module.exports = router ===== Belépési pont ===== Az alkalmazás belépési pontja az index.js fájl, amiben az express biztosítja a szerver indulását. Itt vesszük használatba a routes/api.js fájlban készült útválasztó információkat is. const express = require('express') const app = new express() const router = require('./routes/api') const morgan = require('morgan') require('dotenv').config() const PORT = process.env.APP_PORT || 8000 app.use(morgan('combined')) app.use(express.json()) app.use('/api', router) app.listen(PORT, () => { console.log(`Listening localhost: ${PORT}`) }) A **.env** olvasásához szükség van a **dotenv** csomag beépítésére, a naplózáshoz a **morgan** csomagot használjuk. A process.env.APP_PORT a .env fájlból olvassa az alkalmazás által használandó portot. ===== A package.json ===== { "name": "simpleapi", "version": "1.0.0", "main": "index.js", "license": "MIT", "scripts": { "start": "nodemon app --watch app" }, "dependencies": { "dotenv": "^16.1.4", "express": "^4.18.2", "mariadb": "^3.1.2", "morgan": "^1.10.0", "sequelize": "^6.32.0" }, "devDependencies": { "nodemon": "^2.0.22" } } ===== Futtatás ===== npm start ===== Teszt ===== A HTTPie paranccsal: http localhost:8000/api/employees ===== Linkek ===== * https://github.com/vaclav18/express-api-mariadb (2023)