Saltar al contenido principal
Cómo construir una API REST con Node.js desde cero

Cómo construir una API REST con Node.js desde cero

tutoriales 6/4/2026 8 min Dualsym

Una API REST es la columna vertebral de casi cualquier aplicación moderna. Es la forma en que el frontend habla con el backend, en que dos sistemas intercambian información y en que construyes servicios que otros pueden consumir.

En este tutorial vas a construir una API REST funcional con Node.js y Express desde cero. Al final tendrás un servidor corriendo con rutas reales, manejo de errores y una estructura que escala.

Lo que necesitas antes de empezar

  • Node.js instalado (versión 18 o superior)
  • Un editor de código (VS Code recomendado)
  • Conocimientos básicos de JavaScript
  • Terminal / línea de comandos

Si tienes todo eso, empezamos.

Paso 1: Inicializar el proyecto

Crea una carpeta para tu proyecto y ábrela en la terminal:

mkdir mi-api
cd mi-api
npm init -y

El flag -y acepta todos los valores por defecto. Esto crea tu package.json.

Ahora instala Express, el framework más usado para construir APIs con Node.js:

npm install express

Para desarrollo, también instala nodemon, que reinicia el servidor automáticamente cuando haces cambios:

npm install --save-dev nodemon

Abre package.json y agrega este script:

"scripts": {
  "dev": "nodemon index.js",
  "start": "node index.js"
}

Paso 2: Crear el servidor base

Crea un archivo index.js en la raíz del proyecto:

const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

// Middleware para parsear JSON
app.use(express.json());

// Ruta de prueba
app.get('/', (req, res) => {
  res.json({ mensaje: 'API funcionando correctamente' });
});

// Iniciar servidor
app.listen(PORT, () => {
  console.log(`Servidor corriendo en http://localhost:${PORT}`);
});

Ejecuta npm run dev y abre http://localhost:3000 en tu navegador. Deberías ver el JSON de respuesta.

Paso 3: Organizar la estructura del proyecto

Para que la API escale, necesitas una estructura ordenada desde el inicio. Crea estas carpetas:

mi-api/
├── index.js
├── routes/
│   └── tareas.js
├── controllers/
│   └── tareasController.js
└── data/
    └── tareas.js

Esta separación sigue el patrón MVC (Model-View-Controller) adaptado para APIs:

  • routes/ define las URLs disponibles
  • controllers/ contiene la lógica de cada endpoint
  • data/ simula una base de datos (por ahora en memoria)

Paso 4: Crear los datos de ejemplo

En data/tareas.js, crea un array que hará las veces de base de datos:

let tareas = [
  { id: 1, titulo: 'Aprender Node.js', completada: false },
  { id: 2, titulo: 'Construir una API', completada: false },
  { id: 3, titulo: 'Publicar en producción', completada: false }
];

module.exports = tareas;

Paso 5: Crear el controlador

En controllers/tareasController.js, escribe la lógica para cada operación CRUD:

let tareas = require('../data/tareas');

// Obtener todas las tareas
const getTareas = (req, res) => {
  res.json(tareas);
};

// Obtener una tarea por ID
const getTareaById = (req, res) => {
  const tarea = tareas.find(t => t.id === parseInt(req.params.id));
  if (!tarea) {
    return res.status(404).json({ error: 'Tarea no encontrada' });
  }
  res.json(tarea);
};

// Crear una nueva tarea
const createTarea = (req, res) => {
  const { titulo } = req.body;
  if (!titulo) {
    return res.status(400).json({ error: 'El título es obligatorio' });
  }
  const nuevaTarea = {
    id: tareas.length + 1,
    titulo,
    completada: false
  };
  tareas.push(nuevaTarea);
  res.status(201).json(nuevaTarea);
};

// Actualizar una tarea
const updateTarea = (req, res) => {
  const tarea = tareas.find(t => t.id === parseInt(req.params.id));
  if (!tarea) {
    return res.status(404).json({ error: 'Tarea no encontrada' });
  }
  const { titulo, completada } = req.body;
  if (titulo !== undefined) tarea.titulo = titulo;
  if (completada !== undefined) tarea.completada = completada;
  res.json(tarea);
};

// Eliminar una tarea
const deleteTarea = (req, res) => {
  const index = tareas.findIndex(t => t.id === parseInt(req.params.id));
  if (index === -1) {
    return res.status(404).json({ error: 'Tarea no encontrada' });
  }
  tareas.splice(index, 1);
  res.status(204).send();
};

module.exports = { getTareas, getTareaById, createTarea, updateTarea, deleteTarea };

Paso 6: Definir las rutas

En routes/tareas.js, conecta las URLs con los controladores:

const express = require('express');
const router = express.Router();
const {
  getTareas,
  getTareaById,
  createTarea,
  updateTarea,
  deleteTarea
} = require('../controllers/tareasController');

router.get('/', getTareas);
router.get('/:id', getTareaById);
router.post('/', createTarea);
router.put('/:id', updateTarea);
router.delete('/:id', deleteTarea);

module.exports = router;

Paso 7: Conectar las rutas al servidor

Actualiza index.js para usar las rutas:

const express = require('express');
const tareasRoutes = require('./routes/tareas');
const app = express();
const PORT = process.env.PORT || 3000;

app.use(express.json());

// Rutas
app.use('/api/tareas', tareasRoutes);

// Manejo de rutas no encontradas
app.use((req, res) => {
  res.status(404).json({ error: 'Ruta no encontrada' });
});

app.listen(PORT, () => {
  console.log(`Servidor corriendo en http://localhost:${PORT}`);
});

Paso 8: Probar la API

Con el servidor corriendo, puedes probar los endpoints con herramientas como Postman, Insomnia o con curl desde la terminal:

# Obtener todas las tareas
curl http://localhost:3000/api/tareas

# Crear una tarea
curl -X POST http://localhost:3000/api/tareas \
  -H "Content-Type: application/json" \
  -d '{"titulo": "Nueva tarea"}'

# Actualizar una tarea
curl -X PUT http://localhost:3000/api/tareas/1 \
  -H "Content-Type: application/json" \
  -d '{"completada": true}'

# Eliminar una tarea
curl -X DELETE http://localhost:3000/api/tareas/1

Próximos pasos

Con esta base tienes una API funcional y bien estructurada. Para llevarla a producción, los siguientes pasos naturales son conectar una base de datos real (PostgreSQL o MongoDB), agregar autenticación con JWT, implementar validación robusta de datos con una librería como zod o joi, y configurar variables de entorno con dotenv.

Cada uno de esos temas merece su propio tutorial, pero lo importante es que ya tienes los fundamentos sólidos.

El mejor código es el que entiende quien lo escribe. Construir desde cero, aunque parezca más lento al inicio, produce ese entendimiento.