En aquest tema, aprendrem a desenvolupar una plataforma de blogs utilitzant Node.js i Express. Aquest projecte ens permetrà aplicar molts dels conceptes apresos al llarg del curs, com ara la gestió de rutes, l'autenticació, la interacció amb bases de dades i la creació d'APIs RESTful.

Objectius del Tema

  • Crear una aplicació de blogs amb Node.js i Express.
  • Implementar operacions CRUD (Crear, Llegir, Actualitzar, Eliminar) per a les entrades del blog.
  • Gestionar l'autenticació i l'autorització dels usuaris.
  • Utilitzar una base de dades per emmagatzemar les dades del blog.
  • Implementar una interfície d'usuari bàsica per interactuar amb l'API.

Requisits Previs

  • Coneixements bàsics de Node.js i Express.
  • Familiaritat amb MongoDB i Mongoose.
  • Comprensió de les operacions CRUD.
  • Coneixements bàsics d'HTML i CSS per a la interfície d'usuari.

Passos per Desenvolupar la Plataforma de Blogs

  1. Configuració del Projecte

1.1. Crear l'Estructura del Projecte

mkdir blog-platform
cd blog-platform
npm init -y
npm install express mongoose body-parser bcryptjs jsonwebtoken

1.2. Estructura de Carpetes

blog-platform/
│
├── models/
│   ├── user.js
│   └── post.js
│
├── routes/
│   ├── auth.js
│   └── posts.js
│
├── controllers/
│   ├── authController.js
│   └── postController.js
│
├── middleware/
│   └── authMiddleware.js
│
├── views/
│   ├── index.html
│   └── post.html
│
├── app.js
└── config.js

  1. Configuració de l'Aplicació

2.1. Crear app.js

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

const app = express();

// Middleware
app.use(bodyParser.json());

// Conectar a MongoDB
mongoose.connect(config.dbUri, { useNewUrlParser: true, useUnifiedTopology: true })
    .then(() => console.log('MongoDB connected'))
    .catch(err => console.log(err));

// Rutes
const authRoutes = require('./routes/auth');
const postRoutes = require('./routes/posts');

app.use('/api/auth', authRoutes);
app.use('/api/posts', postRoutes);

const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));

2.2. Crear config.js

module.exports = {
    dbUri: 'mongodb://localhost:27017/blog-platform',
    jwtSecret: 'your_jwt_secret'
};

  1. Models

3.1. Model d'Usuari (models/user.js)

const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

const UserSchema = new mongoose.Schema({
    username: { type: String, required: true, unique: true },
    password: { type: String, required: true }
});

UserSchema.pre('save', async function(next) {
    if (!this.isModified('password')) return next();
    const salt = await bcrypt.genSalt(10);
    this.password = await bcrypt.hash(this.password, salt);
    next();
});

UserSchema.methods.matchPassword = async function(password) {
    return await bcrypt.compare(password, this.password);
};

module.exports = mongoose.model('User', UserSchema);

3.2. Model de Post (models/post.js)

const mongoose = require('mongoose');

const PostSchema = new mongoose.Schema({
    title: { type: String, required: true },
    content: { type: String, required: true },
    author: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
    createdAt: { type: Date, default: Date.now }
});

module.exports = mongoose.model('Post', PostSchema);

  1. Rutes i Controladors

4.1. Rutes d'Autenticació (routes/auth.js)

const express = require('express');
const { register, login } = require('../controllers/authController');
const router = express.Router();

router.post('/register', register);
router.post('/login', login);

module.exports = router;

4.2. Controlador d'Autenticació (controllers/authController.js)

const User = require('../models/user');
const jwt = require('jsonwebtoken');
const config = require('../config');

exports.register = async (req, res) => {
    const { username, password } = req.body;
    try {
        const user = new User({ username, password });
        await user.save();
        res.status(201).json({ message: 'User registered successfully' });
    } catch (err) {
        res.status(400).json({ error: err.message });
    }
};

exports.login = async (req, res) => {
    const { username, password } = req.body;
    try {
        const user = await User.findOne({ username });
        if (!user || !(await user.matchPassword(password))) {
            return res.status(401).json({ message: 'Invalid credentials' });
        }
        const token = jwt.sign({ id: user._id }, config.jwtSecret, { expiresIn: '1h' });
        res.json({ token });
    } catch (err) {
        res.status(400).json({ error: err.message });
    }
};

4.3. Middleware d'Autenticació (middleware/authMiddleware.js)

const jwt = require('jsonwebtoken');
const config = require('../config');
const User = require('../models/user');

exports.protect = async (req, res, next) => {
    let token;
    if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) {
        token = req.headers.authorization.split(' ')[1];
    }
    if (!token) {
        return res.status(401).json({ message: 'Not authorized' });
    }
    try {
        const decoded = jwt.verify(token, config.jwtSecret);
        req.user = await User.findById(decoded.id);
        next();
    } catch (err) {
        res.status(401).json({ message: 'Not authorized' });
    }
};

4.4. Rutes de Posts (routes/posts.js)

const express = require('express');
const { getPosts, createPost, updatePost, deletePost } = require('../controllers/postController');
const { protect } = require('../middleware/authMiddleware');
const router = express.Router();

router.route('/')
    .get(getPosts)
    .post(protect, createPost);

router.route('/:id')
    .put(protect, updatePost)
    .delete(protect, deletePost);

module.exports = router;

4.5. Controlador de Posts (controllers/postController.js)

const Post = require('../models/post');

exports.getPosts = async (req, res) => {
    try {
        const posts = await Post.find().populate('author', 'username');
        res.json(posts);
    } catch (err) {
        res.status(400).json({ error: err.message });
    }
};

exports.createPost = async (req, res) => {
    const { title, content } = req.body;
    try {
        const post = new Post({ title, content, author: req.user._id });
        await post.save();
        res.status(201).json(post);
    } catch (err) {
        res.status(400).json({ error: err.message });
    }
};

exports.updatePost = async (req, res) => {
    const { id } = req.params;
    const { title, content } = req.body;
    try {
        const post = await Post.findById(id);
        if (!post) {
            return res.status(404).json({ message: 'Post not found' });
        }
        if (post.author.toString() !== req.user._id.toString()) {
            return res.status(401).json({ message: 'Not authorized' });
        }
        post.title = title;
        post.content = content;
        await post.save();
        res.json(post);
    } catch (err) {
        res.status(400).json({ error: err.message });
    }
};

exports.deletePost = async (req, res) => {
    const { id } = req.params;
    try {
        const post = await Post.findById(id);
        if (!post) {
            return res.status(404).json({ message: 'Post not found' });
        }
        if (post.author.toString() !== req.user._id.toString()) {
            return res.status(401).json({ message: 'Not authorized' });
        }
        await post.remove();
        res.json({ message: 'Post removed' });
    } catch (err) {
        res.status(400).json({ error: err.message });
    }
};

  1. Interfície d'Usuari

5.1. Crear views/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Blog Platform</title>
</head>
<body>
    <h1>Welcome to the Blog Platform</h1>
    <div id="posts"></div>
    <script>
        async function fetchPosts() {
            const response = await fetch('/api/posts');
            const posts = await response.json();
            const postsDiv = document.getElementById('posts');
            postsDiv.innerHTML = posts.map(post => `
                <div>
                    <h2>${post.title}</h2>
                    <p>${post.content}</p>
                    <p>Author: ${post.author.username}</p>
                </div>
            `).join('');
        }
        fetchPosts();
    </script>
</body>
</html>

  1. Resum

En aquest tema, hem creat una plataforma de blogs utilitzant Node.js i Express. Hem configurat l'estructura del projecte, creat models per a usuaris i posts, implementat rutes i controladors per gestionar l'autenticació i les operacions CRUD, i hem creat una interfície d'usuari bàsica per mostrar les entrades del blog. Aquest projecte ens ha permès aplicar molts dels conceptes apresos al llarg del curs i ens ha proporcionat una base sòlida per desenvolupar aplicacions web amb Node.js.

Exercicis Pràctics

  1. Ampliar la Funcionalitat de l'Aplicació:

    • Afegir la funcionalitat per a que els usuaris puguin comentar les entrades del blog.
    • Implementar la funcionalitat de "like" per a les entrades del blog.
  2. Millorar la Interfície d'Usuari:

    • Utilitzar un framework CSS com Bootstrap per millorar l'aparença de la interfície d'usuari.
    • Afegir formularis per crear i editar entrades del blog des de la interfície d'usuari.
  3. Seguretat:

    • Implementar la validació de dades al servidor per assegurar-se que les entrades del blog continguin informació vàlida.
    • Utilitzar HTTPS per assegurar la comunicació entre el client i el servidor.
  4. Desplegament:

    • Desplegar l'aplicació a una plataforma com Heroku o Vercel.
    • Configurar variables d'entorn per gestionar la configuració de l'aplicació en diferents entorns (desenvolupament, producció).

Solucions als Exercicis

Les solucions als exercicis pràctics es poden trobar a la documentació oficial de Node.js, Express, i MongoDB, així com en diversos tutorials i recursos en línia. Es recomana als estudiants que intentin resoldre els exercicis per si mateixos abans de buscar les solucions, ja que això els ajudarà a consolidar els coneixements adquirits.

Curs de Node.js

Mòdul 1: Introducció a Node.js

Mòdul 2: Conceptes Bàsics

Mòdul 3: Sistema de Fitxers i I/O

Mòdul 4: HTTP i Servidors Web

Mòdul 5: NPM i Gestió de Paquets

Mòdul 6: Framework Express.js

Mòdul 7: Bases de Dades i ORMs

Mòdul 8: Autenticació i Autorització

Mòdul 9: Proves i Depuració

Mòdul 10: Temes Avançats

Mòdul 11: Desplegament i DevOps

Mòdul 12: Projectes del Món Real

© Copyright 2024. Tots els drets reservats