Backend con Node.js Express + CRUD API REST + MySQL

En este post aprenderá como crear proyecto de NodeJS con el framework Express con buena practica y arquitectura limpia.

Crear proyecto y instalación

Comandos para crear proyecto de NodeJS

// crear una carpeta
$ mkdir node-api-rest-mysql
// acceder la carpeta carpeta
$ cd node-api-rest-mysql
// iniciar node
$ npm init -y

Instalar todas las dependencias y librería

$ npm install express --save
$ npm install sequelize --save
$ npm install mysql2 --save 
$ npm install nodemon --save
$ npm install dotenv --save
$ npm install cors --save

App

src\app.js

const express = require('express');
const dotenv = require('dotenv');
const cors = require('cors');

dotenv.config();
const app = express();

const routerApi = require('./routes');

const port = process.env.PORT || 3000;

app.use(cors());
app.use(express.json());

app.get('/', (req,res) => {
    res.send('Backend con NodeJS - Express + CRUD API REST + MySQL');
});

routerApi(app);

app.listen(port,()=>{
    console.log("Port ==> ", port);
});

Package.json

"dev": "nodemon src/app.js",

Config

src\config\config.js

require('dotenv').config();

const config = {
  env: process.env.NODE_ENV || 'dev',
  port: process.env.PORT || 3000,
  dbUser:  process.env.DB_USER,
  dbPassword:  process.env.DB_PASSWORD,
  dbHost:  process.env.DB_HOST,
  dbName:  process.env.DB_NAME,
  dbPort:  process.env.DB_PORT,
}

module.exports = { config };

Model

src\db\models\persons.model.js

const { Model, DataTypes, Sequelize } = require('sequelize');

const PERSON_TABLE = 'persons';

class Person extends Model {
    static config(sequelize) {
        return {
            sequelize,
            tableName: PERSON_TABLE,
            modelName: 'Person',
            timestamps: true
        }
    }
} 

const PersonSchema = {
    id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: DataTypes.INTEGER
    },
    name: {
        allowNull: false,
        type: DataTypes.STRING,
        field:'name'
    },
    address:{ 
        allowNull:false,
        type: DataTypes.STRING,
        field: 'address'
    },
    phone:{
        allowNull: true,
        type: DataTypes.INTEGER,
        field: 'phone'
    } 
}
  
module.exports = { Person, PersonSchema };

src\db\models\index.js

const { Person, PersonSchema } = require('./persons.model');

function setupModels(sequelize) {
    Person.init(PersonSchema, Person.config(sequelize));
}

module.exports = setupModels;

Sequelize

src\libs\sequelize.js

const { Sequelize } = require('sequelize');

const  { config } = require('../config/config');
const setupModels = require('./../db/models');
  
const sequelize = new Sequelize(
    config.dbName, // name database
    config.dbUser, // user database
    config.dbPassword, // password database
    {
      host: config.dbHost,
      dialect: 'mysql' 
    }
  );

sequelize.sync();
setupModels(sequelize);

module.exports = sequelize;

Service

src\services\persons.service.js

const { models } = require('../libs/sequelize');

class PersonsService { 
  
    constructor() {}

    async find() {
      const res = await models.Person.findAll();
      return res;
    }

    async findOne(id) {
      const res = await models.Person.findByPk(id);
      return res;
    }

    async create(data) {
      const res = await models.Person.create(data);
      return res;
    }

    async update(id, data) {
      const model = await this.findOne(id);
      const res = await model.update(data);
      return res;
    }

    async delete(id) {
      const model = await this.findOne(id);
      await model.destroy();
      return { deleted: true };
    }
  
  }
  
  module.exports = PersonsService;

Controller

src\controllers\persons.controller.js

const PersonsService = require('../services/persons.service');
const service = new PersonsService();

const create = async ( req, res ) => {
    try { 
        const response = await service.create(req.body);
        res.json({ success: true, data: response});
    } catch (error) {
        res.status(500).send({ success: false, message: error.message });
    }
}

const get = async ( req, res ) => {
    try {
        const response = await service.find();
        res.json(response);
    } catch (error) {
        res.status(500).send({ success: false, message: error.message });
    }
}

const getById = async ( req, res ) => {
    try {
        const { id } = req.params;
        const response = await service.findOne(id);
        res.json(response);
    } catch (error) {
        res.status(500).send({ success: false, message: error.message });
    }
}

const update = async (req, res) => {
    try {
        const { id } = req.params;
        const body = req.body;
        const response = await service.update(id,body);
        res.json(response);
    } catch (error) {
        res.status(500).send({ success: false, message: error.message });
    }
}

const _delete = async (req, res) => {
    try {
        const { id } = req.params; 
        const response = await service.delete(id);
        res.json(response);
    } catch (error) {
        res.status(500).send({ success: false, message: error.message });
    }
}

module.exports = {
    create, get, getById, update, _delete
};

Router

src\routes\person.router.js

const express = require('express');
const router = express.Router(); 
const personsController = require('../controllers/persons.controller');

router
    .get('/', personsController.get )
    .get('/:id', personsController.getById )
    .post('/', personsController.create )
    .put('/:id', personsController.update )
    .delete('/:id', personsController._delete );

module.exports = router;

src\routes\index.js

const express = require('express'); 

const personsRouter = require('./person.router');

function routerApi(app) {
  const router = express.Router();
  app.use('/api/v1', router); 
  router.use('/persons', personsRouter);
}

module.exports = routerApi;

.env

PORT=3000
DB_USER='root'
DB_PASSWORD=''
DB_HOST='localhost'
DB_NAME='tutofox'
DB_PORT='3306'

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *