En la programación, el experto en información, o el principio de experto, es un enfoque que se utiliza para determinar dónde delegar responsabilidades. En otras palabras, ¿dónde debe colocar el código que completa tareas específicas? El principio de experto en información ayudará a un desarrollador a colocar la responsabilidad en la clase con la mayor cantidad de información necesaria para cumplirla. En este tutorial vamos a limpiar el proceso de generación de JSON Web Tokens para que nuestro código sea más claro y fácil de mantener.
Eliminar código duplicado
Si ha estado siguiendo nuestro tutorial de registro de usuario para Node.js, sabe que actualmente estamos generando un JWT en más de un lugar. Tanto users.js como auth.js están realizando una tarea utilizando un código cortador de cookies. Debemos extraer esa lógica para que solo haya un lugar que genere el token. De esa manera, si algo cambia en el futuro, los realiza en un solo lugar, no en muchos. En nuestro caso, podemos agregar un método a un modelo de Mongoose para hacer esto.
Adición de un método a un modelo de mangosta
En este momento, el modelo de usuario se ve así.
/models/user.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | const Joi = require('joi'); const mongoose = require('mongoose'); const User = mongoose.model('User', new mongoose.Schema({ name: { type: String, required: true, minlength: 5, maxlength: 50 }, email: { type: String, required: true, minlength: 5, maxlength: 255, unique: true }, password: { type: String, required: true, minlength: 5, maxlength: 1024 } })); function validateUser(user) { const schema = { name: Joi.string().min(5).max(50).required(), email: Joi.string().min(5).max(255).required().email(), password: Joi.string().min(5).max(255).required() }; return Joi.validate(user, schema); } exports.User = User; exports.validate = validateUser; |
En el código anterior, el segundo argumento de la función mongoose.model () es una nueva instancia de mongoose.Schema (). Lo primero que debemos hacer es extraer esto a su propia constante así.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | const userSchema = new mongoose.Schema({ name: { type: String, required: true, minlength: 5, maxlength: 50 }, email: { type: String, required: true, minlength: 5, maxlength: 255, unique: true }, password: { type: String, required: true, minlength: 5, maxlength: 1024 } }); |
Con eso en su lugar, configurar el usuario ahora es una simple cuestión de esta línea.
| const User = mongoose.model('User', userSchema); |
Añadiendo el método al modelo de mangosta
Podemos agregar el método ahora al userSchema así.
| userSchema.methods.generateAuthToken = function () { const token = jwt.sign({_id: this._id}, config.get('PrivateKey')); return token; }; |
El modelo de usuario ahora debe funcionar con los paquetes config y jsonwebtoken, por lo que nos aseguramos de incluirlos en la parte superior del archivo. El resto del código se explica por sí mismo con respecto a la extracción del esquema de usuario, la adición de un nuevo método y luego la creación de un nuevo modelo de usuario.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | const config = require('config'); const jwt = require('jsonwebtoken'); const Joi = require('joi'); const mongoose = require('mongoose'); // Extract Schema to it's own constant const userSchema = new mongoose.Schema({ name: { type: String, required: true, minlength: 5, maxlength: 50 }, email: { type: String, required: true, minlength: 5, maxlength: 255, unique: true }, password: { type: String, required: true, minlength: 5, maxlength: 1024 }, }); // Information Expert Principle (add method to model) userSchema.methods.generateAuthToken = function () { const token = jwt.sign({ _id: this._id }, config.get('PrivateKey')); return token; }; // Create new user model const User = mongoose.model('User', userSchema); function validateUser(user) { const schema = { name: Joi.string().min(5).max(50).required(), email: Joi.string().min(5).max(255).required().email(), password: Joi.string().min(5).max(255).required() }; return Joi.validate(user, schema); } exports.User = User; exports.validate = validateUser; |
Ahora tenemos un buen método que podemos usar en otros lugares de nuestro código. Así que ahora observe los cambios en auth.js y users.js. Básicamente, hemos eliminado el código comentado y lo hemos reemplazado con una llamada a user.generateAuthToken ().
/routes/auth.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | const Joi = require('joi'); const bcrypt = require('bcrypt'); const _ = require('lodash'); const { User } = require('../models/user'); const express = require('express'); const router = express.Router(); router.post('/', async (req, res) => { // First Validate The HTTP Request const { error } = validate(req.body); if (error) { return res.status(400).send(error.details[0].message); } // Now find the user by their email address let user = await User.findOne({ email: req.body.email }); if (!user) { return res.status(400).send('Incorrect email or password.'); } // Then validate the Credentials in MongoDB match // those provided in the request const validPassword = await bcrypt.compare(req.body.password, user.password); if (!validPassword) { return res.status(400).send('Incorrect email or password.'); } // const token = jwt.sign({ _id: user._id }, config.get('PrivateKey')); const token = user.generateAuthToken(); res.send(token); }); function validate(req) { const schema = { email: Joi.string().min(5).max(255).required().email(), password: Joi.string().min(5).max(255).required() }; return Joi.validate(req, schema); } module.exports = router; |
/routes/users.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | const bcrypt = require('bcrypt'); const _ = require('lodash'); const { User, validate } = require('../models/user'); const express = require('express'); const router = express.Router(); router.post('/', async (req, res) => { // First Validate The Request const { error } = validate(req.body); if (error) { return res.status(400).send(error.details[0].message); } // Check if this user already exisits let user = await User.findOne({ email: req.body.email }); if (user) { return res.status(400).send('That user already exisits!'); } else { // Insert the new user if they do not exist yet user = new User(_.pick(req.body, ['name', 'email', 'password'])); const salt = await bcrypt.genSalt(10); user.password = await bcrypt.hash(user.password, salt); await user.save(); // const token = jwt.sign({ _id: user._id }, config.get('PrivateKey')); const token = user.generateAuthToken(); res.header('x-auth-token', token).send(_.pick(user, ['_id', 'name', 'email'])); } }); module.exports = router; |
¡Fantástico!
Probando The Refactor con Postman
Ese fue un buen refactor, pero debemos asegurarnos de que la API aún funcione como se esperaba. Aquí probamos con Postman enviando una nueva solicitud de publicación a http: // localhost: 4000 / api / users / con un objeto JSON en el cuerpo para un nuevo usuario. Tenga en cuenta que obtenemos un objeto de usuario adecuado en la respuesta, ¡así que esto significa que funcionó!
Agregar un método a un resumen del modelo de Mongoose
En este tutorial, vimos rápidamente cómo agregar un método a un modelo de Mongoose para reducir el código duplicado en otras áreas de nuestra aplicación. Puede agregar tantos métodos como sea necesario siempre que tenga sentido y siga el Principio de experto en información.
0 Comentarios