Saltar al contenido
Curso de Node.js y APIs
Todos los cursos Ir al ejercicio →

API REST y verbos HTTP

  • ⏱ 60 minutos
  • 📶 Nivel: intermedio
  • 🧩 Incluye ejercicio

💡 🎯 Al terminar esta lección podrás…

  • Explicar qué es un recurso y qué hace cada verbo HTTP.
  • Distinguir PUT de PATCH y entender la idempotencia.
  • Construir un CRUD completo con Express.
  • Elegir el código de estado correcto en cada caso.
  • Probar tu API con curl o una extensión.

1.Qué es una API REST

Una API es la «puerta» que un programa ofrece para que otros programas lo usen. Una API REST hace eso sobre HTTP: en lugar de páginas para leer, ofrece recursos (tareas, usuarios, productos…) que otros programas piden y modifican, casi siempre en formato JSON.

REST se apoya en dos ideas sencillas:

💡 Consejo · Sustantivos en la URL, verbos en el método

Escribe GET /tareas, no /obtenerTareas. La acción ya la dice el método; la URL solo nombra el recurso, en plural.

VerboRuta de ejemploQué haceÉxito
GET/tareasLista todas las tareas200
GET/tareas/7Devuelve la tarea 7200
POST/tareasCrea una tarea nueva201
PUT/tareas/7Reemplaza la tarea 7 entera200
PATCH/tareas/7Cambia solo algunos campos200
DELETE/tareas/7Borra la tarea 7204

A este conjunto de operaciones se le llama CRUD: Create (crear), Read (leer), Update (actualizar) y Delete (borrar). Puedes ver la definición oficial de cada método en MDN.

2.Seguros e idempotentes

Dos propiedades explican por qué cada verbo se usa como se usa:

Verbo¿Seguro? (no modifica datos)¿Idempotente? (repetirlo deja el mismo resultado)
GETSíSí
POSTNoNo: cada llamada crea otro recurso
PUTNoSí: reemplazar dos veces con lo mismo da igual
PATCHNoDepende de cómo se use
DELETENoSí: borrar algo ya borrado no cambia nada más

Por eso un navegador puede repetir un GET sin riesgo (por ejemplo, al recargar), pero te avisa antes de reenviar un POST: podría crear un pedido duplicado.

PUT frente a PATCH

Imagina la tarea { "id": 7, "titulo": "Comprar pan", "hecha": false }:

Dos formas de marcarla como hecha
PUT   /tareas/7   cuerpo: { "titulo": "Comprar pan", "hecha": true }   // hay que enviar TODO
PATCH /tareas/7   cuerpo: { "hecha": true }                           // solo lo que cambia

PUT sustituye el recurso completo (lo que no envíes desaparece); PATCH fusiona los cambios con lo que ya había.

3.Un CRUD completo en memoria

Vamos a construir una API de tareas. Para empezar, guardamos los datos en un array en memoria: es lo más simple, aunque se pierde al reiniciar el servidor (en el proyecto final los guardaremos en un archivo).

index.js
import express from "express";

const app = express();
app.use(express.json());

let tareas = [
  { id: 1, titulo: "Aprender Express", hecha: false },
  { id: 2, titulo: "Crear mi primera API", hecha: false },
];
let siguienteId = 3;

// LEER todas
app.get("/tareas", (req, res) => {
  res.json(tareas);
});

// LEER una
app.get("/tareas/:id", (req, res) => {
  const tarea = tareas.find((t) => t.id === Number(req.params.id));
  if (!tarea) return res.status(404).json({ error: "Tarea no encontrada" });
  res.json(tarea);
});

// CREAR
app.post("/tareas", (req, res) => {
  const { titulo } = req.body ?? {};
  if (typeof titulo !== "string" || titulo.trim() === "") {
    return res.status(400).json({ error: "El título es obligatorio" });
  }
  const nueva = { id: siguienteId++, titulo: titulo.trim(), hecha: false };
  tareas.push(nueva);
  res.status(201).json(nueva);
});

// REEMPLAZAR
app.put("/tareas/:id", (req, res) => {
  const i = tareas.findIndex((t) => t.id === Number(req.params.id));
  if (i === -1) return res.status(404).json({ error: "Tarea no encontrada" });
  const { titulo, hecha } = req.body ?? {};
  if (typeof titulo !== "string" || typeof hecha !== "boolean") {
    return res.status(400).json({ error: "Se requieren titulo y hecha" });
  }
  tareas[i] = { id: tareas[i].id, titulo, hecha };
  res.json(tareas[i]);
});

// MODIFICAR parcialmente
app.patch("/tareas/:id", (req, res) => {
  const tarea = tareas.find((t) => t.id === Number(req.params.id));
  if (!tarea) return res.status(404).json({ error: "Tarea no encontrada" });
  const { titulo, hecha } = req.body ?? {};
  if (titulo !== undefined) tarea.titulo = titulo;
  if (hecha !== undefined) tarea.hecha = hecha;
  res.json(tarea);
});

// BORRAR
app.delete("/tareas/:id", (req, res) => {
  const i = tareas.findIndex((t) => t.id === Number(req.params.id));
  if (i === -1) return res.status(404).json({ error: "Tarea no encontrada" });
  tareas.splice(i, 1);
  res.sendStatus(204);
});

app.listen(3000, () => console.log("API en http://localhost:3000"));

Fíjate en los patrones que se repiten: buscar el recurso, responder 404 si no existe, validar los datos y responder 400 si están mal, y por último actuar y devolver el código correcto.

⚠️ Importante · Validar siempre

Nunca guardes lo que llega en req.body sin comprobarlo. Aquí solo mirábamos el tipo del título; en la lección 7 verás cómo validar de forma más completa.

4.Probar tu API

Con el servidor en marcha, prueba cada verbo. En macOS, Linux o Git Bash:

Terminal
curl http://localhost:3000/tareas
curl -X POST http://localhost:3000/tareas -H "Content-Type: application/json" -d '{"titulo":"Probar mi API"}'
curl -X PATCH http://localhost:3000/tareas/1 -H "Content-Type: application/json" -d '{"hecha":true}'
curl -X DELETE http://localhost:3000/tareas/2 -i
Salida esperada
[{"id":1,"titulo":"Aprender Express","hecha":false},{"id":2,"titulo":"Crear mi primera API","hecha":false}]
{"id":3,"titulo":"Probar mi API","hecha":false}
{"id":1,"titulo":"Aprender Express","hecha":true}
HTTP/1.1 204 No Content

Si prefieres una interfaz gráfica, extensiones del editor (también en Cursor) como REST Client o Thunder Client permiten escribir y enviar peticiones sin recordar la sintaxis de curl. En PowerShell usa curl.exe (y escapa las comillas del JSON, como viste en la lección 4).

Mientras tanto, practica en el navegador la lógica del CRUD con este editor, que usa solo JavaScript puro:

▶ CRUD sobre un array
Consola

5.Buenas prácticas de diseño

Filtrar con query en GET /tareas
app.get("/tareas", (req, res) => {
  let resultado = tareas;
  if (req.query.hecha !== undefined) {
    const hecha = req.query.hecha === "true";
    resultado = resultado.filter((t) => t.hecha === hecha);
  }
  res.json(resultado);
});

📌 Nota · Express Router

Para no tener todas las rutas en un archivo, Express ofrece express.Router(): agrupas las rutas de /tareas en un módulo y lo montas con app.use("/tareas", enrutador). Está explicado en la guía de enrutamiento de Express y lo usarás en el proyecto final.

6.Errores frecuentes

📒 Apuntes para llevar

  • Una API REST expone recursos con URLs en plural y usa el verbo para la acción.
  • GET lee, POST crea (201), PUT reemplaza, PATCH modifica parte, DELETE borra (204).
  • GET es seguro e idempotente; POST no es idempotente.
  • CRUD = Create, Read, Update, Delete.
  • Patrón de cada ruta: buscar, 404 si no existe, validar, 400 si es inválido, actuar y responder.
  • Los errores también se devuelven en JSON, con un formato constante.
  • Los filtros van en la query (?hecha=true), no en rutas nuevas.
  • Un array en memoria sirve para aprender; para guardar de verdad se usa un archivo o una base de datos.

7.Glosario

TérminoSignificado
APIConjunto de operaciones que un programa ofrece para que otros lo usen.
RESTEstilo de diseño de APIs basado en recursos con URL y verbos HTTP.
RecursoCosa que gestiona la API (tarea, usuario, producto).
CRUDCrear, leer, actualizar y borrar.
IdempotenteOperación que repetida produce el mismo resultado que una sola vez.
ColecciónRecurso en plural que agrupa varios elementos: /tareas.
PayloadDatos que viajan en el cuerpo de una petición o respuesta.
EndpointCombinación de método y ruta que ofrece la API.

🧠 Comprueba lo aprendido

Elige una respuesta en cada pregunta. Verás al instante si acertaste y por qué.

¿Qué verbo usarías para crear una tarea nueva?

¿Cuál es la diferencia entre PUT y PATCH?

¿Qué código suele devolverse tras borrar con éxito y sin cuerpo?

¿Cuál es una URL de recurso bien diseñada?

¿Por qué POST no es idempotente?

Tu progreso se guarda en este navegador y se refleja en el índice del curso.

💡 🚀 ¡Ahora te toca!

La práctica fija lo aprendido. Pasa al ejercicio de esta lección.

Ir al ejercicio