En este tema, aprenderás a construir una API REST utilizando MongoDB como base de datos. Este módulo te guiará a través de los conceptos y pasos necesarios para crear una API funcional que pueda realizar operaciones CRUD (Crear, Leer, Actualizar, Eliminar) en una base de datos MongoDB.

Objetivos del Tema

  • Comprender los conceptos básicos de una API REST.
  • Configurar un entorno de desarrollo para construir una API REST.
  • Implementar operaciones CRUD utilizando MongoDB.
  • Probar la API REST para asegurar su correcto funcionamiento.

Requisitos Previos

  • Conocimientos básicos de JavaScript y Node.js.
  • Familiaridad con MongoDB y operaciones CRUD.
  • Entorno de desarrollo configurado con Node.js y MongoDB.

Contenido

  1. ¿Qué es una API REST?

Una API REST (Representational State Transfer) es un conjunto de reglas que permiten la comunicación entre sistemas a través de HTTP. Las API RESTful utilizan métodos HTTP estándar como GET, POST, PUT y DELETE para realizar operaciones CRUD.

  1. Configuración del Entorno

Para construir nuestra API REST, utilizaremos Node.js y Express.js como framework de servidor. También utilizaremos Mongoose para interactuar con MongoDB.

Instalación de Node.js y npm

Si no tienes Node.js y npm instalados, puedes descargarlos e instalarlos desde nodejs.org.

Creación del Proyecto

  1. Crea un nuevo directorio para tu proyecto y navega a él:

    mkdir rest-api-mongodb
    cd rest-api-mongodb
    
  2. Inicializa un nuevo proyecto Node.js:

    npm init -y
    
  3. Instala las dependencias necesarias:

    npm install express mongoose body-parser
    

  1. Estructura del Proyecto

Organiza tu proyecto de la siguiente manera:

rest-api-mongodb/
│
├── models/
│   └── item.js
├── routes/
│   └── items.js
├── app.js
└── package.json

  1. Creación del Modelo de Datos

En MongoDB, los datos se almacenan en documentos. Utilizaremos Mongoose para definir un esquema y un modelo para nuestros datos.

models/item.js

const mongoose = require('mongoose');

const itemSchema = new mongoose.Schema({
    name: {
        type: String,
        required: true
    },
    quantity: {
        type: Number,
        required: true
    },
    price: {
        type: Number,
        required: true
    }
});

module.exports = mongoose.model('Item', itemSchema);

  1. Creación de Rutas

Las rutas definen los endpoints de nuestra API y las operaciones que se pueden realizar en ellos.

routes/items.js

const express = require('express');
const router = express.Router();
const Item = require('../models/item');

// Obtener todos los ítems
router.get('/', async (req, res) => {
    try {
        const items = await Item.find();
        res.json(items);
    } catch (err) {
        res.status(500).json({ message: err.message });
    }
});

// Obtener un ítem por ID
router.get('/:id', getItem, (req, res) => {
    res.json(res.item);
});

// Crear un nuevo ítem
router.post('/', async (req, res) => {
    const item = new Item({
        name: req.body.name,
        quantity: req.body.quantity,
        price: req.body.price
    });

    try {
        const newItem = await item.save();
        res.status(201).json(newItem);
    } catch (err) {
        res.status(400).json({ message: err.message });
    }
});

// Actualizar un ítem
router.put('/:id', getItem, async (req, res) => {
    if (req.body.name != null) {
        res.item.name = req.body.name;
    }
    if (req.body.quantity != null) {
        res.item.quantity = req.body.quantity;
    }
    if (req.body.price != null) {
        res.item.price = req.body.price;
    }

    try {
        const updatedItem = await res.item.save();
        res.json(updatedItem);
    } catch (err) {
        res.status(400).json({ message: err.message });
    }
});

// Eliminar un ítem
router.delete('/:id', getItem, async (req, res) => {
    try {
        await res.item.remove();
        res.json({ message: 'Deleted Item' });
    } catch (err) {
        res.status(500).json({ message: err.message });
    }
});

// Middleware para obtener un ítem por ID
async function getItem(req, res, next) {
    let item;
    try {
        item = await Item.findById(req.params.id);
        if (item == null) {
            return res.status(404).json({ message: 'Cannot find item' });
        }
    } catch (err) {
        return res.status(500).json({ message: err.message });
    }

    res.item = item;
    next();
}

module.exports = router;

  1. Configuración del Servidor

Configura el servidor Express para utilizar las rutas que hemos definido.

app.js

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

mongoose.connect('mongodb://localhost/rest-api', { useNewUrlParser: true, useUnifiedTopology: true });
const db = mongoose.connection;
db.on('error', (error) => console.error(error));
db.once('open', () => console.log('Connected to Database'));

app.use(bodyParser.json());

const itemsRouter = require('./routes/items');
app.use('/items', itemsRouter);

app.listen(3000, () => console.log('Server Started'));

  1. Probando la API

Puedes utilizar herramientas como Postman o cURL para probar los endpoints de tu API.

Ejemplo de Peticiones

  • GET /items - Obtener todos los ítems.
  • GET /items/:id - Obtener un ítem por ID.
  • POST /items - Crear un nuevo ítem.
    {
        "name": "Apple",
        "quantity": 10,
        "price": 1.5
    }
    
  • PUT /items/:id - Actualizar un ítem existente.
    {
        "name": "Orange",
        "quantity": 20,
        "price": 2.0
    }
    
  • DELETE /items/:id - Eliminar un ítem.

  1. Ejercicios Prácticos

  1. Ejercicio 1: Añade un nuevo campo description al esquema del ítem y actualiza las rutas para manejar este nuevo campo.
  2. Ejercicio 2: Implementa la paginación en la ruta GET /items para manejar grandes volúmenes de datos.
  3. Ejercicio 3: Añade validaciones adicionales al modelo de datos, como límites de longitud para el nombre y valores mínimos/máximos para la cantidad y el precio.

Soluciones a los Ejercicios

Ejercicio 1: Añadir Campo description

// models/item.js
const itemSchema = new mongoose.Schema({
    name: {
        type: String,
        required: true
    },
    quantity: {
        type: Number,
        required: true
    },
    price: {
        type: Number,
        required: true
    },
    description: {
        type: String,
        required: false
    }
});

Actualiza las rutas para manejar el nuevo campo description.

Ejercicio 2: Implementar Paginación

// routes/items.js
router.get('/', async (req, res) => {
    try {
        const { page = 1, limit = 10 } = req.query;
        const items = await Item.find()
            .limit(limit * 1)
            .skip((page - 1) * limit)
            .exec();
        const count = await Item.countDocuments();
        res.json({
            items,
            totalPages: Math.ceil(count / limit),
            currentPage: page
        });
    } catch (err) {
        res.status(500).json({ message: err.message });
    }
});

Ejercicio 3: Añadir Validaciones

// models/item.js
const itemSchema = new mongoose.Schema({
    name: {
        type: String,
        required: true,
        maxlength: 100
    },
    quantity: {
        type: Number,
        required: true,
        min: 1,
        max: 1000
    },
    price: {
        type: Number,
        required: true,
        min: 0.01
    },
    description: {
        type: String,
        required: false,
        maxlength: 500
    }
});

Conclusión

En este tema, has aprendido a construir una API REST utilizando Node.js, Express y MongoDB. Has configurado el entorno de desarrollo, creado un modelo de datos, definido rutas y probado la API. Además, has realizado ejercicios prácticos para reforzar los conceptos aprendidos. Con esta base, estás preparado para construir aplicaciones más complejas y robustas utilizando MongoDB como base de datos.

© Copyright 2024. Todos los derechos reservados