Tartalomjegyzék

< Express

Express - Sequelize modellek ES

A Sequalize

A Sequelize egy TypeScript és NodeJS alapú ORM a következő adatbázis rendszerek számára:

Webhely:

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ése

npm install sequelize mariadb sqlite3 dotenv morgan
npm install --save-dev nodemon

Környezet

Feltételezzük, hogy van (vagy lesz) 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.

.env
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:

A DB_STORAGE értéke Sqlite esetén szükséges:

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.

A .env.example néven célszerű egy kezdetleges beállítófájlt létrehozni.

Adatbázis

MySQL vagy MariaDB adatbázisban hozzuk létre 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.

app/database/database.js
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,
        dialectOptions: {}
    }
)
 
module.exports = sequelize

A process.env.DB kezdetű sorok, az adatokat a .env fájlból olvassák.

Model definiálása

app/models/employee.js
import { DataTypes } from 'sequelize'
import sequelize from '../database/database.js'
 
const Employee = sequelize.define('employees', {
  id: {
    type: DataTypes.INTEGER,
    primaryKey: true,
    autoIncrement: true
  },
  name: { type: DataTypes.STRING },
  city: { type: DataTypes.STRING },
  salary: { type: DataTypes.DOUBLE }
})
 
await sequelize.sync({
  force: false
})
 
export default 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ánosan használt került ide. A következő linkeken találunk még használható típusokat:

A modell tesztelése

// A létrehozott modell után, a modellfájlban:
await Employee.sync()
await Employee.create({
  name: 'Erős István',
  city: 'Szeged',
  salary: 492
})

Ha kiegészítjük a modellünket a két utasítással, akkor a sync() hívás hatására létre kell jöjjön az adatbázisban az employees táblának. A create() függvény hatására létre kell jönnie egy rekordnak a megadott tartalommal.

Kontroller

Az employeecontroller.js állományban hozzuk létre az EmployeeController-t, ami négy függvényt tartalmaz: index(), store(), update() és destroy().

app/controllers/employeecontroller.js
import Employee from '../models/employee.js'
 
const EmployeeController = {
  async index(req, res) {
    try {
      const employees = await Employee.findAll()
      res.json(employees)
    } catch (error) {
      res.status(500).json({ error: error.message })
    }
  },
 
  async create(req, res) {
    try {
      const employee = await Employee.create(req.body)
      res.status(201).json(employee)
    } catch (error) {
      res.status(500).json({ error: error.message })
    }
  },
 
  async update(req, res) {
    try {
      const employee = await Employee.findByPk(req.params.id)
      if (!employee) {
        return res.status(404).json({ error: 'Employee not found' })
      }
      await employee.update(req.body)
      res.json(employee)
    } catch (error) {
      res.status(500).json({ error: error.message })
    }
  },
 
  async delete(req, res) {
    try {
      const employee = await Employee.findByPk(req.params.id)
      if (!employee) {
        return res.status(404).json({ error: 'Employee not found' })
      }
      await employee.destroy()
      res.json({ message: 'Employee deleted successfully' })
    } catch (error) {
      res.status(500).json({ error: error.message })
    }
  }
}
 
export default 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 szervezni.

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.

app/routes/api.js
import Router from 'express'
const router = Router()
 
import EmployeeController from '../controllers/employeecontroller.js'
 
 
router.get('/employees', EmployeeController.index)
router.post('/employees', EmployeeController.create)
router.put('/employees/:id', EmployeeController.update)
router.delete('/employees/:id', EmployeeController.delete)
 
export default 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.

app/index.js
import express from 'express'
const app = express()
import router from './routes/api.js'
import morgan from 'morgan'
import dotenv from 'dotenv'
dotenv.config()
 
app.use(morgan('dev'))
app.use(express.json())
app.use(router)
 
const PORT=process.env.APP_PORT || 8000
 
app.listen(PORT, () => {
  console.log(`Server running on port ${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": "^17.2.1",
    "express": "^5.1.0",
    "mariadb": "^3.4.5",
    "morgan": "^1.10.1",
    "sequelize": "^6.37.7"
  },
  "devDependencies": {
    "nodemon": "^2.0.22"
  }
}

Futtatás

npm start

Teszt

A resen paranccsal:

res localhost:8000/api/employees

Linkek