En este módulo, aprenderás a desarrollar una plataforma de blogs completa utilizando Node.js y Express. Este proyecto te permitirá aplicar muchos de los conceptos que has aprendido a lo largo del curso, como la gestión de bases de datos, autenticación, enrutamiento y más.
Objetivos del Módulo
- Crear una aplicación de blogs funcional.
- Implementar operaciones CRUD (Crear, Leer, Actualizar, Eliminar) para las publicaciones del blog.
- Gestionar la autenticación y autorización de usuarios.
- Desplegar la aplicación en un entorno de producción.
Estructura del Módulo
Configuración del Proyecto
Paso 1: Inicializar el Proyecto
Primero, crea una nueva carpeta para tu proyecto y navega a ella desde la terminal. Luego, inicializa un nuevo proyecto de Node.js.
Paso 2: Instalar Dependencias
Instala las dependencias necesarias para el proyecto.
Paso 3: Configurar el Servidor
Crea un archivo server.js y configura el servidor básico de Express.
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const app = express();
// Middleware
app.use(bodyParser.json());
// Conectar a la base de datos
mongoose.connect('mongodb://localhost:27017/blog', { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('MongoDB conectado'))
.catch(err => console.log(err));
// Rutas
app.get('/', (req, res) => {
res.send('Bienvenido a la Plataforma de Blogs');
});
// Iniciar el servidor
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Servidor corriendo en el puerto ${PORT}`));Modelado de Datos
Paso 1: Crear el Modelo de Usuario
Crea un archivo models/User.js para definir el esquema del usuario.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const UserSchema = new Schema({
username: {
type: String,
required: true,
unique: true
},
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
}
});
module.exports = mongoose.model('User', UserSchema);Paso 2: Crear el Modelo de Publicación
Crea un archivo models/Post.js para definir el esquema de las publicaciones del blog.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const PostSchema = new Schema({
title: {
type: String,
required: true
},
body: {
type: String,
required: true
},
author: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
},
date: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('Post', PostSchema);Rutas y Controladores
Paso 1: Configurar Rutas de Autenticación
Crea un archivo routes/auth.js para manejar el registro y el inicio de sesión de usuarios.
const express = require('express');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const User = require('../models/User');
const router = express.Router();
// Registro de usuario
router.post('/register', async (req, res) => {
const { username, email, password } = req.body;
try {
let user = await User.findOne({ email });
if (user) {
return res.status(400).json({ msg: 'El usuario ya existe' });
}
user = new User({ username, email, password });
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(password, salt);
await user.save();
const payload = { user: { id: user.id } };
jwt.sign(payload, 'secret', { expiresIn: 3600 }, (err, token) => {
if (err) throw err;
res.json({ token });
});
} catch (err) {
console.error(err.message);
res.status(500).send('Error en el servidor');
}
});
// Inicio de sesión de usuario
router.post('/login', async (req, res) => {
const { email, password } = req.body;
try {
let user = await User.findOne({ email });
if (!user) {
return res.status(400).json({ msg: 'Credenciales inválidas' });
}
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.status(400).json({ msg: 'Credenciales inválidas' });
}
const payload = { user: { id: user.id } };
jwt.sign(payload, 'secret', { expiresIn: 3600 }, (err, token) => {
if (err) throw err;
res.json({ token });
});
} catch (err) {
console.error(err.message);
res.status(500).send('Error en el servidor');
}
});
module.exports = router;Paso 2: Configurar Rutas de Publicaciones
Crea un archivo routes/posts.js para manejar las operaciones CRUD de las publicaciones del blog.
const express = require('express');
const auth = require('../middleware/auth');
const Post = require('../models/Post');
const router = express.Router();
// Crear una nueva publicación
router.post('/', auth, async (req, res) => {
const { title, body } = req.body;
try {
const newPost = new Post({
title,
body,
author: req.user.id
});
const post = await newPost.save();
res.json(post);
} catch (err) {
console.error(err.message);
res.status(500).send('Error en el servidor');
}
});
// Obtener todas las publicaciones
router.get('/', async (req, res) => {
try {
const posts = await Post.find().populate('author', ['username']);
res.json(posts);
} catch (err) {
console.error(err.message);
res.status(500).send('Error en el servidor');
}
});
// Obtener una publicación por ID
router.get('/:id', async (req, res) => {
try {
const post = await Post.findById(req.params.id).populate('author', ['username']);
if (!post) {
return res.status(404).json({ msg: 'Publicación no encontrada' });
}
res.json(post);
} catch (err) {
console.error(err.message);
res.status(500).send('Error en el servidor');
}
});
// Actualizar una publicación
router.put('/:id', auth, async (req, res) => {
const { title, body } = req.body;
try {
let post = await Post.findById(req.params.id);
if (!post) {
return res.status(404).json({ msg: 'Publicación no encontrada' });
}
if (post.author.toString() !== req.user.id) {
return res.status(401).json({ msg: 'No autorizado' });
}
post.title = title;
post.body = body;
await post.save();
res.json(post);
} catch (err) {
console.error(err.message);
res.status(500).send('Error en el servidor');
}
});
// Eliminar una publicación
router.delete('/:id', auth, async (req, res) => {
try {
let post = await Post.findById(req.params.id);
if (!post) {
return res.status(404).json({ msg: 'Publicación no encontrada' });
}
if (post.author.toString() !== req.user.id) {
return res.status(401).json({ msg: 'No autorizado' });
}
await post.remove();
res.json({ msg: 'Publicación eliminada' });
} catch (err) {
console.error(err.message);
res.status(500).send('Error en el servidor');
}
});
module.exports = router;Paso 3: Configurar Middleware de Autenticación
Crea un archivo middleware/auth.js para manejar la autenticación de usuarios.
const jwt = require('jsonwebtoken');
module.exports = function(req, res, next) {
const token = req.header('x-auth-token');
if (!token) {
return res.status(401).json({ msg: 'No hay token, autorización denegada' });
}
try {
const decoded = jwt.verify(token, 'secret');
req.user = decoded.user;
next();
} catch (err) {
res.status(401).json({ msg: 'Token no válido' });
}
};Paso 4: Integrar Rutas en el Servidor
Actualiza server.js para incluir las rutas de autenticación y publicaciones.
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const app = express();
// Middleware
app.use(bodyParser.json());
// Conectar a la base de datos
mongoose.connect('mongodb://localhost:27017/blog', { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('MongoDB conectado'))
.catch(err => console.log(err));
// Rutas
app.use('/api/auth', require('./routes/auth'));
app.use('/api/posts', require('./routes/posts'));
app.get('/', (req, res) => {
res.send('Bienvenido a la Plataforma de Blogs');
});
// Iniciar el servidor
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Servidor corriendo en el puerto ${PORT}`));Autenticación y Autorización
Registro de Usuario
Para registrar un nuevo usuario, envía una solicitud POST a /api/auth/register con el siguiente cuerpo:
{
"username": "usuario1",
"email": "[email protected]",
"password": "password123"
}Inicio de Sesión
Para iniciar sesión, envía una solicitud POST a /api/auth/login con el siguiente cuerpo:
{
"email": "[email protected]",
"password": "password123"
}El servidor responderá con un token JWT que debe ser incluido en el encabezado x-auth-token para las solicitudes autenticadas.
Interfaz de Usuario
Paso 1: Configurar el Cliente
Puedes usar cualquier framework de frontend como React, Angular o Vue.js para construir la interfaz de usuario. Aquí, proporcionaremos un ejemplo básico usando HTML y JavaScript.
Paso 2: Crear Formularios de Registro e Inicio de Sesión
Crea un archivo index.html con formularios para el registro e inicio de sesión.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Plataforma de Blogs</title>
</head>
<body>
<h1>Plataforma de Blogs</h1>
<div>
<h2>Registro</h2>
<form id="registerForm">
<input type="text" id="username" placeholder="Nombre de usuario" required>
<input type="email" id="email" placeholder="Correo electrónico" required>
<input type="password" id="password" placeholder="Contraseña" required>
<button type="submit">Registrar</button>
</form>
</div>
<div>
<h2>Inicio de Sesión</h2>
<form id="loginForm">
<input type="email" id="loginEmail" placeholder="Correo electrónico" required>
<input type="password" id="loginPassword" placeholder="Contraseña" required>
<button type="submit">Iniciar Sesión</button>
</form>
</div>
<script>
document.getElementById('registerForm').addEventListener('submit', async (e) => {
e.preventDefault();
const username = document.getElementById('username').value;
const email = document.getElementById('email').value;
const password = document.getElementById('password').value;
const res = await fetch('/api/auth/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username, email, password })
});
const data = await res.json();
console.log(data);
});
document.getElementById('loginForm').addEventListener('submit', async (e) => {
e.preventDefault();
const email = document.getElementById('loginEmail').value;
const password = document.getElementById('loginPassword').value;
const res = await fetch('/api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ email, password })
});
const data = await res.json();
console.log(data);
});
</script>
</body>
</html>Despliegue
Paso 1: Configurar Variables de Entorno
Crea un archivo .env para almacenar las variables de entorno.
Paso 2: Actualizar server.js para Usar Variables de Entorno
Actualiza server.js para usar las variables de entorno.
require('dotenv').config();
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const app = express();
// Middleware
app.use(bodyParser.json());
// Conectar a la base de datos
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('MongoDB conectado'))
.catch(err => console.log(err));
// Rutas
app.use('/api/auth', require('./routes/auth'));
app.use('/api/posts', require('./routes/posts'));
app.get('/', (req, res) => {
res.send('Bienvenido a la Plataforma de Blogs');
});
// Iniciar el servidor
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Servidor corriendo en el puerto ${PORT}`));Paso 3: Desplegar en Heroku
Sigue los pasos para desplegar tu aplicación en Heroku.
- Inicia sesión en Heroku:
heroku login - Crea una nueva aplicación:
heroku create - Configura las variables de entorno en Heroku:
heroku config:set MONGO_URI=your_mongo_uri JWT_SECRET=your_jwt_secret - Despliega la aplicación:
git push heroku master
Conclusión
En este módulo, has aprendido a desarrollar una plataforma de blogs completa utilizando Node.js y Express. Has implementado operaciones CRUD, autenticación y autorización, y has desplegado la aplicación en un entorno de producción. Este proyecto te ha permitido aplicar muchos de los conceptos que has aprendido a lo largo del curso y te ha preparado para desarrollar aplicaciones web más complejas en el futuro.
Curso de Node.js
Módulo 1: Introducción a Node.js
Módulo 2: Conceptos Básicos
Módulo 3: Sistema de Archivos y E/S
Módulo 4: HTTP y Servidores Web
- Creando un Servidor HTTP Simple
- Manejo de Solicitudes y Respuestas
- Sirviendo Archivos Estáticos
- Enrutamiento
Módulo 5: NPM y Gestión de Paquetes
- Introducción a NPM
- Instalación y Uso de Paquetes
- Creación y Publicación de Paquetes
- Versionado Semántico
Módulo 6: Framework Express.js
- Introducción a Express.js
- Configuración de una Aplicación Express
- Middleware
- Enrutamiento en Express
- Manejo de Errores
Módulo 7: Bases de Datos y ORMs
- Introducción a las Bases de Datos
- Usando MongoDB con Mongoose
- Usando Bases de Datos SQL con Sequelize
- Operaciones CRUD
Módulo 8: Autenticación y Autorización
- Introducción a la Autenticación
- Usando Passport.js
- Autenticación JWT
- Control de Acceso Basado en Roles
Módulo 9: Pruebas y Depuración
- Introducción a las Pruebas
- Pruebas Unitarias con Mocha y Chai
- Pruebas de Integración
- Depuración de Aplicaciones Node.js
Módulo 10: Temas Avanzados
- Módulo Cluster
- Hilos de Trabajo
- Optimización del Rendimiento
- Construcción de APIs RESTful
- GraphQL con Node.js
Módulo 11: Despliegue y DevOps
- Variables de Entorno
- Usando PM2 para la Gestión de Procesos
- Desplegando en Heroku
- Integración y Despliegue Continuos
