API REST y verbos HTTP
💡 🎯 Al terminar esta lección podrás…
- Explicar qué es un recurso y qué hace cada verbo HTTP.
- Distinguir
PUTdePATCHy entender la idempotencia. - Construir un CRUD completo con Express.
- Elegir el código de estado correcto en cada caso.
- Probar tu API con
curlo 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:
- Cada recurso tiene una dirección propia (una URL):
/tareases la colección y/tareas/7es una tarea concreta. - El verbo HTTP indica la acción: leer, crear, reemplazar, modificar o borrar.
💡 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.
| Verbo | Ruta de ejemplo | Qué hace | Éxito |
|---|---|---|---|
GET | /tareas | Lista todas las tareas | 200 |
GET | /tareas/7 | Devuelve la tarea 7 | 200 |
POST | /tareas | Crea una tarea nueva | 201 |
PUT | /tareas/7 | Reemplaza la tarea 7 entera | 200 |
PATCH | /tareas/7 | Cambia solo algunos campos | 200 |
DELETE | /tareas/7 | Borra la tarea 7 | 204 |
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) |
|---|---|---|
GET | Sí | Sí |
POST | No | No: cada llamada crea otro recurso |
PUT | No | Sí: reemplazar dos veces con lo mismo da igual |
PATCH | No | Depende de cómo se use |
DELETE | No | Sí: 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 }:
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).
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:
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
[{"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:
5.Buenas prácticas de diseño
- URLs en plural y en minúsculas:
/tareas,/usuarios/3/pedidos. - Código de estado correcto:
201al crear,204al borrar,404si no existe,400si los datos son inválidos. - Siempre JSON, también en los errores, con un formato constante como
{ "error": "mensaje" }. - Filtros y orden con query:
GET /tareas?hecha=trueen lugar de rutas nuevas. - Sin lógica en las rutas cuando crezca: pasa a funciones o módulos aparte (lo verás en el proyecto final).
- Versiona la API si va a tener clientes externos:
/api/v1/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
- Verbos en la URL (
/crearTarea): usaPOST /tareas. - Responder 200 a todo: crear es
201, borrar suele ser204y lo inexistente404. - Comparar ids de distinto tipo:
req.params.ides texto; conviértelo conNumberantes de comparar con===. - Confundir PUT y PATCH:
PUTexige el recurso completo. - No validar el cuerpo: guardas basura y la API falla más tarde.
- Olvidar
express.json():req.bodyllega sin datos. - Esperar que los datos persistan: un array en memoria desaparece al reiniciar.
📒 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).
GETes seguro e idempotente;POSTno 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érmino | Significado |
|---|---|
| API | Conjunto de operaciones que un programa ofrece para que otros lo usen. |
| REST | Estilo de diseño de APIs basado en recursos con URL y verbos HTTP. |
| Recurso | Cosa que gestiona la API (tarea, usuario, producto). |
| CRUD | Crear, leer, actualizar y borrar. |
| Idempotente | Operación que repetida produce el mismo resultado que una sola vez. |
| Colección | Recurso en plural que agrupa varios elementos: /tareas. |
| Payload | Datos que viajan en el cuerpo de una petición o respuesta. |
| Endpoint | Combinació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?
POST sobre la colección (/tareas) crea un recurso y devuelve 201.
¿Cuál es la diferencia entre PUT y PATCH?
PUT envía el recurso completo; PATCH envía solo lo que cambia.
¿Qué código suele devolverse tras borrar con éxito y sin cuerpo?
204 No Content: todo fue bien y no hay nada que devolver.
¿Cuál es una URL de recurso bien diseñada?
Sustantivo en plural y el id al final; la acción la indica el verbo.
¿Por qué POST no es idempotente?
Enviar dos veces el mismo POST crea dos recursos, así que el resultado cambia.
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.