// Reto: construir una API REST CRUD de "tareas" con un array en memoria.
// Debe soportar GET (listar y uno), POST (crear), PUT (actualizar) y DELETE (borrar),
// devolviendo los status codes correctos.
//
// Entrada / salida esperada (ejemplos):
// GET /tareas -> 200 [ ...lista... ]
// GET /tareas/1 -> 200 { id: 1, ... } o 404 si no existe
// POST /tareas -> 201 { id, titulo, hecha } o 400 si falta titulo
// PUT /tareas/1 -> 200 { ...actualizada... } o 404 si no existe
// DELETE /tareas/1 -> 204 sin cuerpo o 404 si no existe
//
// Como probarlo:
// 1. npm install
// 2. node 06-retos-codigo/crud-in-memory.js
// 3. curl http://localhost:3000/tareas
// curl -X POST http://localhost:3000/tareas -H "Content-Type: application/json" -d '{"titulo":"Estudiar"}'
const express = require("express");
const app = express();
const PORT = process.env.PORT || 3000;
// express.json() es un middleware que parsea el body JSON de la peticion
// y lo deja disponible en req.body. Sin esto, req.body es undefined.
app.use(express.json());
// "Base de datos" en memoria. En un proyecto real seria una base de datos.
let tareas = [
{ id: 1, titulo: "Aprender Express", hecha: false },
{ id: 2, titulo: "Practicar entrevistas", hecha: false },
];
let siguienteId = 3; // para generar ids unicos al crear
// READ (lista): GET /tareas -> 200 con el array completo.
app.get("/tareas", (req, res) => {
res.status(200).json(tareas);
});
// READ (uno): GET /tareas/:id -> 200 si existe, 404 si no.
app.get("/tareas/:id", (req, res) => {
// req.params.id llega como string; lo convertimos a numero para comparar.
const id = Number(req.params.id);
const tarea = tareas.find((t) => t.id === id);
if (!tarea) {
// 404 = recurso no encontrado. Devolvemos un mensaje, nunca un stack trace.
return res.status(404).json({ error: "Tarea no encontrada" });
}
res.status(200).json(tarea);
});
// CREATE: POST /tareas -> 201 (Created) si se creo, 400 si el body es invalido.
app.post("/tareas", (req, res) => {
const { titulo } = req.body;
// Validamos la entrada antes de tocar los datos.
if (!titulo || typeof titulo !== "string") {
return res.status(400).json({ error: "El campo 'titulo' es obligatorio" });
}
const nueva = { id: siguienteId++, titulo, hecha: false };
tareas.push(nueva);
// 201 Created es el status correcto al crear un recurso nuevo.
res.status(201).json(nueva);
});
// UPDATE: PUT /tareas/:id -> 200 si se actualizo, 404 si no existe.
app.put("/tareas/:id", (req, res) => {
const id = Number(req.params.id);
const tarea = tareas.find((t) => t.id === id);
if (!tarea) {
return res.status(404).json({ error: "Tarea no encontrada" });
}
// Actualizamos solo los campos que vengan en el body.
if (req.body.titulo !== undefined) tarea.titulo = req.body.titulo;
if (req.body.hecha !== undefined) tarea.hecha = req.body.hecha;
res.status(200).json(tarea);
});
// DELETE: DELETE /tareas/:id -> 204 (sin cuerpo) si se borro, 404 si no existe.
app.delete("/tareas/:id", (req, res) => {
const id = Number(req.params.id);
const existe = tareas.some((t) => t.id === id);
if (!existe) {
return res.status(404).json({ error: "Tarea no encontrada" });
}
tareas = tareas.filter((t) => t.id !== id);
// 204 No Content: la operacion tuvo exito pero no hay nada que devolver.
res.status(204).end();
});
app.listen(PORT, () => {
console.log(`API CRUD de tareas en http://localhost:${PORT}`);
});
module.exports = app;