CAPÍTULO 4 · Una interfaz que el equipo pueda mantener
Todas las pantallas necesitan entender al mismo servidor
Las vistas del backend ya comparten contratos mediante repoGenerico. Sería extraño perder ese acuerdo en el navegador y hacer que cada pantalla interprete las respuestas con reglas diferentes. Una podría confundir una validación con un fallo de red; otra podría ocultar un rechazo de permisos detrás de un mensaje genérico que no ayuda a continuar.
Concentramos el transporte HTTP en un cliente compartido. Allí distinguimos las respuestas del servidor de los problemas al obtenerlas y devolvemos información que cada módulo pueda presentar. La pantalla conserva la decisión de cómo mostrar su estado, mientras el cliente evita repetir la mecánica de enviar, leer y clasificar respuestas.
Este diálogo común entre frontend y backend facilita agregar funciones. También vuelve más importante una pregunta que estaba presente desde el comienzo: ¿todas las personas deberían poder usar todas esas funciones? Mostrar una interfaz coherente es solo el primer paso; ahora debemos relacionar cada acción con la responsabilidad de quien la ejecuta.
Leer esta parte dentro del relato completo →DEL RELATO A LA PRÁCTICA
Vamos a desarrollar esta decisión con su mapa, explicación, código y ejercicio.
MIRA · CONECTA · COMPRENDE
Un mensajero para todas las llamadas
Las flechas resumen el recorrido conceptual. Los controles y dependencias se detallan debajo.
Selecciona una pieza para destacar su responsabilidad.
Leer la explicación del mapa
- Frontend. Solicita una operación
- Cliente API. Centraliza transporte
- Respuesta. Éxito o error estructurado
- Manejo. Presenta el resultado coherentemente
01 / EL PROBLEMA
¿Para qué sirve?
Una API puede devolver validación, falta de permisos, HTML inesperado o fallo de red. El frontend debe conservar esa información para explicar lo ocurrido.
02 / COMPRENDER
El concepto, explicado
fetch no lanza excepción solo porque HTTP sea 400 o 500. Debes revisar response.ok. JSON inválido y error de red son fallos diferentes.
La abstracción debe devolver datos o lanzar errores de manera consistente. Mezclar success:false con excepciones obliga a cada consumidor a entender dos contratos.
03 / CONSTRUIR
Implementación paso a paso
- Crea requestJSON.
- Revisa status y tipo de respuesta.
- Conserva status en el error.
- Evita duplicar URLs en todos los módulos.
04 / APLICAR
Ejemplo en SensorHub
export async function requestJSON(url, options = {}) {
const response = await fetch(url, {
credentials: "same-origin", ...options,
headers: { Accept: "application/json", ...options.headers }
});
let data;
try { data = await response.json(); }
catch { throw new Error("Respuesta del servidor no válida."); }
if (!response.ok) {
const error = new Error(data.detail || "La operación falló.");
error.status = response.status;
error.data = data;
throw error;
}
return data;
}Cómo leer el ejemplo
- ...options permite método y body; headers se fusiona para no perder Accept.
- El consumidor puede distinguir error.status y errores por campo en error.data.
- Para APIs con sesión, agrega token CSRF en escrituras como se muestra después.
Error habitual
Un redirect a login puede terminar como HTML con status 200. El error JSON debe ser manejado y la sesión debe tener un contrato adecuado para APIs.
05 / PRACTICAR
Tu turno
Muestra un mensaje distinto para HTTP 403.
Ver solución orientativa
Captura el error; si status===403 muestra falta de permisos, y en los demás casos ofrece el mensaje de validación o fallo de conexión.
06 / VERIFICAR
Cómo sabes que funciona
- Errores HTTP no se muestran como operación exitosa.
- No se pierden los mensajes de validación por campo.
CONTINUAR LA EXPERIENCIA
El siguiente paso del recorrido:
Política central de roles y capacidades →Continuar en modo relato