DEV Community 👩‍💻👨‍💻

Roberto Morais
Roberto Morais

Posted on

CRUD de usuarios en NodeJS: Parte 3

Ahora que ya tenemos el servidor de Node levantado y la base de datos en MongoDB operativa, hay que diseñar la entidad de usuario y sus acciones. Para ello vamos a empezar por crear el modelo, pero antes vamos a añadir extensiones que necesitaremos más adelante, empezando por mongoose-unique-validator, que agrega validación previa al guardado para campos únicos dentro de un esquema Mongoose:

   $ npm install --save mongoose-unique-validator
Enter fullscreen mode Exit fullscreen mode

Vamos a instalar también la extensión bcrypt, con ella vamos a cifrar la contraseña para "hashearla". Esto quiere decir que vamos a usar contraseñas con un método de cifrado del tipo hash.

   $ npm install --save bcrypt
Enter fullscreen mode Exit fullscreen mode

Otra librería que nos vendrá muy bien para recuperar los campos de un formulario para actualizar nuestro usuario será underscore y para instalarla lanzamos:

   $ npm install --save underscore
Enter fullscreen mode Exit fullscreen mode

Para acabar, vamos a añadir la librería body-parser que nos permitirá coger cualquier dato (de usuario, paginación, limite para mostrar. etc) que enviemos al servidor al consumir los servicios API Rest, directamente desde el objeto body dentro de req, así req.body.foo. A parte, podemos añadir validaciones de tipo de dato de una manera sencilla. Por ejemplo: req.body.foo.toString()

   $ npm install --save body-parser
Enter fullscreen mode Exit fullscreen mode

Cuando hayamos terminado de instalar las librerías, creamos una carpeta nueva llamada models dentro de la carpeta server:

   $ mkdir server/models
Enter fullscreen mode Exit fullscreen mode

Dentro de la carpeta creamos un fichero llamado User.js, este fichero contendrá el esquema de nuestra entidad usuario y será el encargado de crear este esquema en la base de datos:

const mongoose = require('mongoose');
const uniqueValidator = require('mongoose-unique-validator');

let Schema = mongoose.Schema;

let userSchema = new Schema({
    name: {
        type: String,
        required: [true, 'El nombre es requerido']
    },
    email:{
        type: String,
        unique: true,
        required: [true, 'El correo electrónico es requerido']
    },
    password: {
        type: String,
        required: [true, 'La contraseña es requerido']
    },
    img: {
        type: String,
        required: false
    },
    status: {
        type: Boolean,
        default: true
    }
});

userSchema.methods.toJSON = function(){
    let user = this;
    let userObject = user.toObject();
    delete userObject.password;
    return userObject;
}

userSchema.plugin(uniqueValidator, {
    message: '{PATH} debe de ser único'
});

module.exports = mongoose.model('User', userSchema);
Enter fullscreen mode Exit fullscreen mode

Una vez hayamos creado el modelo volemos a crear una carpeta nueva llamada routes, dentro de server y al mismo nivel que models.

   $ mkdir server/routes
Enter fullscreen mode Exit fullscreen mode

Dentro de ella vamos a crear un fichero llamado users.js, y será el fichero que contendrá las acciones que se pueden hacer sobre nuestros usuarios. Es el fichero que contiene las acciones del CRUD. Los servicios serán del tipo:

  • POST para crear.
  • PUT para editar.
  • GET para listar.
  • DELETE para borrar o desactivar un usuario.

Este fichero user.js contiene lo siguiente:

const express = require('express');
const bcrypt = require('bcrypt');
const _ = require('underscore');
const User = require('../models/User');
const app = express();

// Listado de usuarios
app.get('/usuario', (req, res) => {

    let from = req.query.from || 0;
    from = Number(from);

    let limit = req.query.limit || 5;
    limit = Number(limit);

    let conditions = {
        status: true
    }

    User.find(conditions, 'name email status')
        .skip(from)
        .limit(limit)
        .exec((err, users) => {
        if(err){
            return res.status(400).json({
               ok: false,
               err  
            });
        }

        User.countDocuments(conditions,(err, sumUsers) => {
            res.json({
                ok: true,
                users,
                sumUsers
            });
        });
    });
});

// Crear usuario
app.post('/usuario', (req, res) => {
    let body = req.body;

    let user = new User({
        name: body.name,
        email: body.email,
        password: bcrypt.hashSync(body.password, 10)
    });

    user.save((err, userDB) => {
        if(err){
            return res.status(400).json({
               ok: false,
               err  
            });
        }

        res.json({
            ok: true,
            usuario: userDB
        });
    });
});

// Actualizar usuario
app.put('/usuario/:id', (req, res) => {
    let id = req.params.id;
    let body = _.pick(req.body, ['name', 'email', 'img', 'status']);

    User.findByIdAndUpdate(id, body, {new: true, runValidators: true}, (err, userBD) => {
        if(err){
            return res.status(400).json({
               ok: false,
               err  
            });
        }

        res.json({
            ok: true,
            usuario: userBD
        });
    });
});

// Eliminar/Desactivar usuario
app.delete('/usuario/:id', (req, res) => {
    let id = req.params.id;
    User.findByIdAndUpdate(id, {status: false}, {new: true}, (err, userBD) => {
        if(err){
            return res.status(400).json({
               ok: false,
               err  
            });
        }

        if(!userBD){
            return res.status(400).json({
                ok: false,
                err:{
                    message: 'Usuario no encontrado'
                } 
             });
        }

        res.json({
            ok: true,
            userBD
        });
    });
});

module.exports = app;
Enter fullscreen mode Exit fullscreen mode

En mi caso, no quiero eliminar ningún usuario, así que el DELETE es para desactivar cambiando el estado del usuario por false.
Ahora, para poder usar este controlador que tiene las funciones de nuestro CRUD, hay que importarlo en nuestro fichero server.js con la siguiente línea de código:

app.use(require('./routes/users'));
Enter fullscreen mode Exit fullscreen mode

Además hay que importar la librería que hemos instalado antes, llamada body-parser, que nos permitirá acceder a los datos de una manera más sencilla:

const bodyParser = require('body-parser');
Enter fullscreen mode Exit fullscreen mode

De este modo, nuestro fichero server.js quedará así:

    const express = require('express');
    const mongoose = require('mongoose');
    const bodyParser = require('body-parser');

    // Parse application/x-www-form-urlencoded
    app.use(bodyParser.urlencoded({ extended: false }));
    // Parse application/json
    app.use(bodyParser.json());
    // Include controller of the entity
    app.use(require('./routes/users'));

    const run = async () => {
        await mongoose.connect(SERVER_BBDD, {
            useNewUrlParser: true,
            useUnifiedTopology: true,
            useCreateIndex: true,
        });
    };

    run().catch(error => console.error(error));

    app.listen(process.env.PORT, () => {
         console.log(`Escuchando en el puerto 3000`);
    });
Enter fullscreen mode Exit fullscreen mode

Una vez tengamos nuestro servidor levantado, podemos hacer las peticiones para crear, editar, desactivar o listar los usuarios registrados en nuestra base de datos de mangodb. En mi caso, uso Postman y aquí puedes encontrar una breve documentación de los comandos que uso para ejecutar las apis que acabamos de hacer. Esto es lo básico funcional para tener un CRUD completo de usuarios.

Top comments (0)

This post blew up on DEV in 2020:

js visualized

🚀⚙️ JavaScript Visualized: the JavaScript Engine

As JavaScript devs, we usually don't have to deal with compilers ourselves. However, it's definitely good to know the basics of the JavaScript engine and see how it handles our human-friendly JS code, and turns it into something machines understand! 🥳

Happy coding!