- La estructura de la URL funciona no solo como una dirección simple, sino también como un medio para almacenar y restaurar el estado de una aplicación
- Se presenta el caso de la página de descarga de PrismJS, donde una sola URL reproduce por completo la configuración de tema, lenguaje y plugins
- Cada componente, como la ruta, los parámetros de consulta y el fragmento, expresa distintos tipos de estado, como navegación jerárquica, filtrado y navegación del cliente
- Filtros de búsqueda, paginación, modo de vista y rango de fechas son adecuados para incluirse en la URL, mientras que la información sensible o estados temporales de la UI no lo son
- Una URL bien diseñada mejora la capacidad de compartir, la previsibilidad y la eficiencia del caché, y refuerza la confiabilidad y la experiencia de usuario de las aplicaciones web
El potencial de la URL
- La URL no es solo la dirección de un recurso, sino que también funciona como una interfaz de usuario (UI) y un contenedor de estado
- Conserva automáticamente el estado al compartir, guardar en marcadores, usar el historial del navegador y crear deep links
- Ha funcionado como el mecanismo básico de gestión de estado de la web desde 1991
- Cada componente de la URL representa un tipo distinto de estado
- Ruta (Path): exploración jerárquica de recursos (
/users/123/posts)
- Consulta (Query): filtros, opciones y configuraciones (
?theme=dark&lang=en)
- Fragmento (Fragment): ubicación dentro del documento o enrutamiento SPA (
#features, #/dashboard)
- La función de Text Fragments permite enlazar directamente a un texto específico dentro de una página
Patrones de parámetros de consulta
- Método de usar un delimitador (delimiter) para poner varios valores en una sola clave (
?tags=frontend,react,hooks)
- Serialización de datos anidados en JSON o Base64 (
?config=eyJyaWNrIjoicm9sbCJ9==)
- Los flags booleanos se expresan con la sola presencia de la clave (
?mobile)
- La notación de arreglos (bracket notation) expresa múltiples valores en la forma
tags[]=frontend&tags[]=react
- Se reconoce automáticamente en
qs de Node o en middlewares de Express, pero no está estandarizada
- La clave está en mantener la consistencia
Casos de representación de estado mediante la URL
- PrismJS: guarda toda la configuración de tema, lenguaje y plugins en el hash de la URL
- GitHub: resalta un rango específico de líneas de código con
#L108-L136
- Google Maps: incluye coordenadas, nivel de zoom y tipo de mapa en la URL
- Figma: comparte mediante URL el contexto de trabajo, como la posición del lienzo, el zoom y los elementos seleccionados
- Sitios de comercio electrónico: incluyen filtros, ordenamiento y rango de precios en la URL para restaurar el estado de búsqueda
Patrones de ingeniería frontend
- Estado adecuado para incluir en la URL
- término de búsqueda, filtros, página y orden, modo de vista, rango de fechas, pestaña activa, configuración de UI, flags de funciones
- Estado inadecuado para la URL
- información sensible como contraseñas o tokens, estados temporales de UI, entradas no guardadas, datos de gran tamaño, estados de alta frecuencia
- Criterio de decisión: ¿otro usuario debería ver el mismo estado al hacer clic en la misma URL?
Implementación en JavaScript
- La API
URLSearchParams permite leer y escribir parámetros de consulta
pushState agrega una nueva entrada al historial y replaceState actualiza la actual
- El evento
popstate restaura la UI al usar el botón Atrás del navegador
Implementación en React
- El hook
useSearchParams de React Router permite gestionar de forma concisa el estado en la URL
- Al leer o actualizar parámetros, sincroniza automáticamente la URL y la UI
Buenas prácticas para gestionar estado con la URL
- No incluir valores predeterminados en la URL (mantener solo
?theme=dark; los valores por defecto se resuelven en el código)
- Evitar actualizaciones excesivas de la URL durante la escritura mediante debouncing (usando
lodash.debounce)
- pushState vs replaceState
pushState: para estados reversibles, como cambios de filtro o navegación entre páginas
replaceState: para ajustes finos, como la entrada de búsqueda
Ver la URL como un contrato (Contract)
- Una URL bien diseñada actúa como un contrato explícito entre la aplicación y el usuario
- Aclara los límites entre estados públicos/privados, cliente/servidor y compartidos/de sesión
- Una URL legible comunica la intención y puede ser entendida tanto por personas como por máquinas
- Una forma como
example.com/products/laptop?color=silver&sort=price transmite mejor el significado
- Mejora de la eficiencia del caché
- La misma URL se considera el mismo recurso, lo que aumenta la tasa de aciertos en caché
- Los parámetros de consulta permiten controlar variantes de caché
- Versionado y experimentos
?v=2, ?beta=true, ?experiment=new-ui permiten distinguir versiones de API y pruebas A/B
Antipatrones que se deben evitar
- Mantener el estado solo en memoria en una SPA, perdiéndolo al recargar la página
- Incluir información sensible en la URL (
?password=secret123)
- Nombres de parámetros poco claros (
?foo=true&bar=2 en lugar de ?mobile=true&page=2)
- Codificar JSON complejo en Base64, generando URLs excesivamente largas
- Superar el límite de longitud de la URL (existen restricciones de navegadores, servidores y CDN)
- Anular el botón Atrás (puede ocurrir por abuso de
replaceState)
Conclusión
- Una buena URL hace más que apuntar a contenido: expresa una conversación entre el usuario y la aplicación
- La URL es el medio de gestión de estado más antiguo y elegante para contener intención, contexto y posibilidad de compartir
- Aunque existen herramientas complejas de gestión de estado como Redux, MobX, Zustand y Recoil,
no olvidar esta capacidad básica de la URL es una de las verdaderas fortalezas de la web
- Una app que pierde el estado al recargar está pasando por alto una característica esencial de la web
2 comentarios
Opiniones en Hacker News
En las revisiones de código intento guardar la mayor cantidad posible de estado (state) en la URL
Que después de recargar te mande a un lugar completamente distinto, o que una URL compartida muestre una pantalla equivocada, es ofensivo desde la perspectiva del usuario
Este enfoque ralentiza el desarrollo, pero dentro del equipo eleva la conciencia sobre UX y deja más claro cuánto estado estamos metiendo en la vista
También existe la preocupación de que la URL se convierta en una especie de API pública y eso imponga restricciones, pero creo que no es un gran problema porque la mayoría de las URL solo se usan a corto plazo
Si hace falta, se puede resolver con código que al cargar migra la URL anterior a una nueva
Creo que usar query parameters en vez de la ruta (path) funciona un poco mejor
Desde la perspectiva del usuario, la palabra “atrás” está asociada al botón del navegador, así que eso genera confusión
Que al recargar se reinicie el estado molesta menos, porque existe la idea de que “recargar = empezar de nuevo”
Cuando todo se maneja con JS, estas funciones básicas se rompen de forma sutil
Pero incluso después de trabajar con más de 30 diseñadores UX, nunca he recibido una guía sobre URL
Sobre todo en móvil, donde es difícil devolver una página a su estado inicial, recargar termina siendo la solución más rápida
En interfaces con scroll infinito o filtros complejos, cuanto más estado haya en la URL, más tedioso se vuelve reiniciar todo
Si el usuario ya está molesto con la UX y además tiene que ordenar la URL, eso le genera un estrés doble
Siento que incluso las personas con alta alfabetización digital tienen poca comprensión de las URL y el DNS
Deberían ser capaces de reducir el riesgo de phishing, entender el significado de parámetros de URL (
?t=_,utm_) y eliminar información personal antes de compartirlasTambién deberían saber que el candado de HTTPS no significa ‘confianza’
Si usas la URL como contenedor de estado, la estructura interna queda expuesta y hace falta versionado
También puede haber problemas en la compatibilidad entre navegadores o en los flujos de autenticación
Aun así, intento exponer en la URL la mayor cantidad de estado posible, como si fueran argumentos de línea de comandos
Pero este es un trade-off intencional, no el resultado de ignorancia o falta de experiencia
Recomiendo Rison, una librería antigua pero todavía útil
Permite guardar JSON de forma limpia en la URL y también se usa en Kibana de Elastic
Ejemplo: http://example.com/service?query=q:'*',start:10,count:10
A medida que un sistema evoluciona, también cambia la estructura del estado, así que meterlo en la URL limita esa evolución
Eso se debe a que la URL es básicamente una cadena permanente
En cambio, creo que lo apropiado es ver la URL como una especie de protocolo y codificar/decodificar el estado
Si la página es simple, incluso es posible meter todo el estado en la URL
Pero en algo como un feed depende de las expectativas del usuario, por ejemplo: “¿al recargar debería volver al estado más reciente?”
El límite de longitud de una URL varía según la configuración del navegador, el servidor, el CDN o el motor de búsqueda, pero normalmente está por debajo de 2000 caracteres
Eso hace pensar cuánta información de estado se puede meter ahí, o si hace falta otro enfoque
- . _ ~), así que la densidad de información es bastante altadraw.io puede guardar el estado completo en la URL para compartirlo
Los datos del diagrama se codifican en Base64, así que con un solo enlace se puede restaurar todo por completo
Aunque no estoy seguro de que eso encaje con la definición de ‘state container’
En mis apps self-hosted uso hash routing (#/dashboard)
No hace falta reescritura de URL del lado del servidor (.htaccess, etc.), así que aunque no es perfecto, reduce las restricciones del entorno de despliegue
La versión moderna de Microsoft Teams maneja todas las pantallas con una sola URL, así que no se pueden marcar
Es muy incómodo no poder abrir directamente un equipo o canal específico
HATEOAS no llama mucho la atención porque su nombre no ayuda, pero al final es un concepto básico de la web
Pero en entornos donde controlas tanto el servidor como el cliente, solo añade complejidad extra
Sobre todo si el cliente igual necesita conocer la estructura de los endpoints, porque entonces la URL solo se vuelve opaca
Uso mucho la función de suspensión de pestañas, pero las webapps que fijan todo en una sola URL y se mueven como un bloque pierden la información cuando entran en suspensión.
Pero además, esas páginas web siempre son pesadas, así que tampoco puedes no ponerlas en suspensión.