node js, logo, nodejs, javascript, source code, program, development, node js, node js, node js, node js, nodejs, nodejs, nodejs, nodejs, nodejs, javascript, javascript, javascript, javascript

Guía Práctica: API REST con Express.js y NeDB

SofiDev

Angela Sofía Osorio

Tiempo de lectura 2 minutes

Guía Práctica: API REST con Express.js y NeDB

1. Configuración Inicial

import express from 'express';
import NeDB from 'nedb';
import util from 'util';

const PORT = import.meta?.env?.PORT || 3000; // Puerto desde variables de entorno o 3000
JavaScript
  • Módulos clave:
  • express: Framework para crear el servidor web.
  • nedb: Base de datos NoSQL embebida (similar a MongoDB).
  • util: Para convertir callbacks en Promesas.

2. Inicializar Express

const app = express();
app.use(express.json()); // Middleware para parsear JSON
JavaScript
  • Middleware esencial:
  • Sin express.json(), las peticiones POST/PUT no podrán leer el cuerpo en formato JSON.

3. Configuración Detallada de NeDB

Paso 1: Extender la clase NeDB

export class LocalDB extends NeDB {
    constructor(options) {
        super(options); // Hereda constructor de NeDB
        // Promisificación de métodos
        this.removeAsync = util.promisify(this.remove.bind(this));
        this.insertAsync = util.promisify(this.insert.bind(this));
        this.updateAsync = util.promisify(this.update.bind(this));
        this.findAsync = util.promisify(this.find.bind(this));
        this.findOneAsync = util.promisify(this.findOne.bind(this));
    }
}
JavaScript
  • ¿Por qué bind(this)?
  • Mantiene el contexto de la instancia al ejecutar métodos.
  • Sin esto, obtendrías errores como Cannot read property 'exec' of undefined.
  • Métodos promisificados:
  • Permiten usar async/await en lugar de callbacks. Ejemplo:
    javascript await SURVERY_DB.insertAsync({ key: 'value' }); // Operación bloqueante

Paso 2: Crear Instancia de la Base de Datos

export const SURVERY_DB = new LocalDB({
    filename: './src/database/survery.db', // Archivo físico de datos
    autoload: true // Carga automática al iniciar
});
JavaScript
  • Parámetros clave:
  • filename: Ruta del archivo de almacenamiento (creado automáticamente si no existe).
  • autoload: true: Carga los datos al instanciar la base.
  • Estructura de documentos:
  • Cada documento tiene un _id único de 16 caracteres (ej: hT4sLm9Pq6R2vX7z).
  • Almacenamiento en disco: Persistente entre reinicios del servidor.

4. Endpoints CRUD

POST /options – Crear Documento

app.post('/options', async ({ body }, res) => {
    const { key, ...rest } = body;
    if (!key) return res.status(401).send(); // Validación simple
    try {
        const result = await SURVERY_DB.insertAsync(rest); // Insertar sin key
        res.json(result);
    } catch (error) {
        res.status(500).send('Error interno');
    }
});
JavaScript
  • Validación mínima: Campo key obligatorio.
  • Uso típico:
  curl -X POST http://localhost:3000/options -H "Content-Type: application/json" -d '{"key": "secret", "name": "Ejemplo"}'
JavaScript

GET /option/:id – Obtener Documento por ID

app.get('/option/:id', async ({ params }, res) => {
    const { id } = params;
    if (!/^\w{16}$/.test(id)) return res.status(400).send(); // Validación con regex
    try {
        const { _id, ...result } = await SURVERY_DB.findOneAsync({ _id: id });
        res.json(result); // Excluye _id en la respuesta
    } catch {
        res.status(404).send();
    }
});
JavaScript
  • Regex /^\w{16}$/: Asegura que el ID tenga 16 caracteres alfanuméricos.

GET /options – Listar Todos los Documentos

app.get('/options', async (_, res) => {
    try {
        const result = await SURVERY_DB.findAsync({}); // Consulta vacía = todos los documentos
        res.json(result);
    } catch {
        res.status(404).send();
    }
});
JavaScript

5. Manejo de Errores

  • Códigos HTTP claros:
  • 400: ID mal formateado.
  • 401: Falta campo obligatorio.
  • 404: Documento no existe.
  • 500: Error interno del servidor.
  • Buenas prácticas:
  • En producción, evita enviar detalles de errores internos al cliente.
  • Usa logs para diagnóstico: console.error(error).

6. Iniciar el Servidor

app.listen(PORT, () => {
    console.log(`\x1b[33mServidor activo en http://localhost:${PORT}/\x1b[39m`);
});
JavaScript
  • ANSI escape codes: \x1b[33m (amarillo) y \x1b[39m (reset color).

Recap

Este setup ofrece una API funcional con:

  • Persistencia de datos (NeDB).
  • Validaciones básicas (regex, campos obligatorios).
  • Manejo moderno de async/await.