37 points par GN⁺ 2025-11-03 | 2 commentaires | Partager sur WhatsApp
  • La structure d’une URL ne se limite pas à une simple adresse : elle sert aussi de moyen pour stocker et restaurer l’état d’une application
  • Présentation d’un cas comme la page de téléchargement de PrismJS, où une seule URL permet de reproduire entièrement les réglages de thème, de langage et de plugins
  • Les différents composants comme le chemin, les paramètres de requête et le fragment expriment divers états, comme la navigation hiérarchique, le filtrage ou la navigation côté client
  • Les filtres de recherche, la pagination, le mode d’affichage et la plage de dates se prêtent bien à une inclusion dans l’URL, contrairement aux informations sensibles ou à un état d’interface temporaire
  • Une URL bien conçue améliore la partageabilité, la prévisibilité et l’efficacité du cache, et renforce la fiabilité de l’application web ainsi que l’expérience utilisateur

Le potentiel de l’URL

  • L’URL n’est pas seulement l’adresse d’une ressource : elle fait aussi office d’interface utilisateur (UI) et de conteneur d’état
    • Elle préserve automatiquement l’état pour le partage, les favoris, l’historique du navigateur et les deep links
    • Depuis 1991, elle sert de mécanisme fondamental de gestion d’état sur le Web
  • Chaque composant de l’URL exprime un type d’état différent
    • Chemin (Path) : navigation hiérarchique dans les ressources (/users/123/posts)
    • Requête (Query) : filtres, options et réglages (?theme=dark&lang=en)
    • Fragment (Fragment) : position dans un document ou routage SPA (#features, #/dashboard)
  • La fonctionnalité Text Fragments permet de créer un lien direct vers un texte précis dans une page

Modèles de paramètres de requête

  • Utiliser un délimiteur (delimiter) pour regrouper plusieurs valeurs sous une seule clé (?tags=frontend,react,hooks)
  • Sérialiser des données imbriquées en JSON ou en Base64 (?config=eyJyaWNrIjoicm9sbCJ9==)
  • Représenter les indicateurs booléens par la seule présence de la clé (?mobile)
  • La notation en crochets (bracket notation) permet de représenter plusieurs valeurs sous la forme tags[]=frontend&tags[]=react
    • Elle est reconnue automatiquement par qs de Node ou certains middlewares Express, mais n’est pas standardisée
  • L’essentiel est de rester cohérent

Exemples de représentation d’état via l’URL

  • PrismJS : stocke l’ensemble des réglages de thème, de langage et de plugins dans le hash de l’URL
  • GitHub : met en évidence une plage précise de lignes de code avec #L108-L136
  • Google Maps : inclut les coordonnées, le niveau de zoom et le type de carte dans l’URL
  • Figma : partage le contexte de travail — position sur le canevas, zoom, éléments sélectionnés — via l’URL
  • Sites e-commerce : intègrent les filtres, le tri et la plage de prix dans l’URL pour restaurer l’état de recherche

Modèles d’ingénierie frontend

  • États qui se prêtent bien à l’URL
    • terme de recherche, filtres, pagination et tri, mode d’affichage, plage de dates, onglet actif, configuration UI, feature flags
  • États inadaptés à l’URL
    • informations sensibles comme les mots de passe ou tokens, état UI temporaire, saisies non enregistrées, données volumineuses, états à très haute fréquence
  • Critère de décision : si un autre utilisateur clique sur la même URL, doit-il voir le même état ?

Implémentation JavaScript

  • L’API URLSearchParams permet de lire et d’écrire les paramètres de requête
  • pushState ajoute une nouvelle entrée dans l’historique, replaceState met à jour l’entrée courante
  • L’événement popstate permet de restaurer l’UI lors d’un retour arrière dans le navigateur

Implémentation React

  • Le hook useSearchParams de React Router permet de gérer simplement l’état dans l’URL
    • La lecture et la mise à jour des paramètres synchronisent automatiquement l’URL et l’UI

Bonnes pratiques de gestion d’état via l’URL

  • Ne pas inclure les valeurs par défaut dans l’URL (ne conserver que ?theme=dark, et gérer les valeurs par défaut dans le code)
  • Utiliser le debouncing pour éviter des mises à jour excessives de l’URL pendant la saisie (lodash.debounce)
  • pushState vs replaceState
    • pushState : pour les états réversibles comme un changement de filtre ou un changement de page
    • replaceState : pour les modifications fines comme la saisie dans un champ de recherche

Considérer l’URL comme un contrat

  • Une URL bien conçue joue le rôle de contrat explicite entre l’application et l’utilisateur
    • Elle clarifie les frontières entre public/privé, client/serveur et état partagé/session
  • Une URL lisible exprime l’intention et reste compréhensible à la fois pour les humains et les machines
    • Une forme comme example.com/products/laptop?color=silver&sort=price transmet clairement le sens
  • Amélioration de l’efficacité du cache
    • Une même URL étant considérée comme une même ressource, le taux de hit du cache augmente
    • Les paramètres de requête permettent aussi de contrôler les variantes de cache
  • Versioning et expérimentation
    • ?v=2, ?beta=true, ?experiment=new-ui permettent de distinguer version d’API et tests A/B

Anti-patterns à éviter

  • Conserver l’état uniquement en mémoire dans une SPA, ce qui le fait disparaître au rechargement
  • Inclure des informations sensibles dans l’URL (?password=secret123)
  • Utiliser des noms de paramètres peu explicites (?foo=true&bar=2 au lieu de ?mobile=true&page=2)
  • Encoder un JSON complexe en Base64, ce qui produit des URL excessivement longues
  • Dépasser les limites de longueur d’URL (contraintes côté navigateur, serveur et CDN)
  • Neutraliser le bouton retour (cas fréquent en abusant de replaceState)

Conclusion

  • Une bonne URL ne se contente pas de pointer vers un contenu : elle exprime une conversation entre l’utilisateur et l’application
  • L’URL est l’un des moyens de gestion d’état les plus anciens et les plus élégants pour porter l’intention, le contexte et le caractère partageable
  • Des outils complexes de gestion d’état comme Redux, MobX, Zustand ou Recoil existent, mais
    ne pas oublier cette capacité native de l’URL reste l’une des vraies forces du Web
  • Une application qui perd son état au rechargement passe à côté d’une propriété essentielle du Web

2 commentaires

 
GN⁺ 2025-11-03
Commentaires sur Hacker News
  • Lors des revues de code, j’essaie de stocker autant que possible l’état (state) dans l’URL
    Après un rafraîchissement, être envoyé à un endroit complètement différent, ou voir une URL partagée afficher un écran sans rapport, est insultant du point de vue de l’utilisateur
    Cette approche ralentit le développement, mais elle améliore la sensibilité UX au sein de l’équipe et permet de voir clairement combien d’état est encapsulé dans la vue
    Certains craignent que l’URL devienne une sorte d’API publique, avec les contraintes que cela implique, mais je pense que ce n’est généralement pas un gros problème, car la plupart des URL ne sont utilisées qu’à court terme
    Si nécessaire, on peut le résoudre avec du code qui migre les anciennes URL vers les nouvelles au chargement

    • J’aime bien cette approche, mais l’autocomplétion de l’historique du navigateur peut parfois rappeler un état non souhaité
      Je pense que c’est un peu mieux avec des paramètres de requête plutôt qu’avec le chemin (path)
    • Une webapp métier que j’utilise a créé son propre bouton « retour », ce qui casse complètement le bouton retour du navigateur
      Pour l’utilisateur, le mot « retour » est naturellement associé au bouton du navigateur, donc c’est déroutant
      Qu’un rafraîchissement réinitialise l’état est moins agaçant. Il y a l’idée que « rafraîchir = repartir de zéro »
    • Sur une page rendue côté serveur, la position de défilement est automatiquement restaurée au rafraîchissement
      Quand tout est géré en JS, ce genre de fonctionnalités de base se dégrade subtilement
    • Je pense que la conception des URL fait partie du design UX
      Pourtant, même après avoir travaillé avec plus de 30 designers UX, je n’ai jamais reçu de consignes sur les URL
    • À mesure que le web a évolué, le sens de “rafraîchir” a changé selon les contextes
      En particulier sur mobile, il est difficile de remettre une page dans son état initial, donc le rafraîchissement devient la solution la plus rapide
      Avec l’infinite scroll ou des interfaces de filtres complexes, plus il y a d’état dans l’URL, plus la réinitialisation devient pénible
      Si l’UX pose déjà problème et qu’en plus il faut remettre de l’ordre dans l’URL, cela ajoute un stress supplémentaire pour l’utilisateur
  • J’ai l’impression que même les personnes ayant une forte culture numérique comprennent mal les URL et le DNS
    Elles devraient être capables de réduire les risques de phishing, de comprendre la signification des paramètres d’URL (?t=_, utm_) et de retirer les informations personnelles avant de partager
    Il faut aussi comprendre que le cadenas HTTPS ne signifie pas « confiance »

    • Mais c’est difficile à enseigner quand les navigateurs masquent ou abrègent les URL par défaut, et que les entreprises ne promeuvent que des QR codes ou des mots-clés de recherche
  • Utiliser l’URL comme conteneur d’état expose la structure interne et impose de gérer les versions
    Cela peut aussi poser problème pour la compatibilité entre navigateurs ou les flux d’authentification
    Malgré cela, j’essaie d’exposer autant d’état que possible dans l’URL, un peu comme des arguments de ligne de commande
    Mais c’est un trade-off assumé, pas le résultat de l’ignorance ou d’un manque d’expérience

  • C’est une vieille bibliothèque mais elle reste utile : Rison
    Elle permet de stocker proprement du JSON dans une URL, et elle est aussi utilisée dans Kibana d’Elastic
    Exemple : http://example.com/service?query=q:'*',start:10,count:10

    • C’est exactement le genre de chose que je cherchais ! Avant, je bricolais quelque chose moi-même, mais ça a l’air bien plus standardisé et propre
  • Quand un système évolue, la structure de l’état change aussi ; mettre l’état dans l’URL contraint donc cette évolution
    Parce qu’une URL est fondamentalement une chaîne pérenne
    À la place, je pense qu’il vaut mieux considérer l’URL comme une sorte de protocole, avec un mécanisme d’encodage et de décodage de l’état
    Pour une page simple, il est possible d’y mettre l’état complet

    • Pour les contenus à longue durée de vie (par ex. un billet de blog), préserver l’état dans l’URL est utile
      Mais pour un flux, cela dépend des attentes de l’utilisateur, par exemple : « un rafraîchissement doit-il revenir à l’état le plus récent ? »
    • Introduire du versioning peut atténuer ce genre de problème
  • Les limites de longueur des URL varient selon le navigateur, le serveur, le CDN ou le moteur de recherche, mais on parle généralement de moins de 2000 caractères
    Cela amène à se demander combien d’état on peut réellement y faire tenir, ou s’il faut une autre approche

    • En excluant le domaine, chaque caractère peut prendre 66 valeurs (majuscules/minuscules, chiffres, caractères spéciaux - . _ ~), donc la densité d’information reste assez élevée
  • draw.io peut stocker l’état complet dans l’URL afin de le partager
    Les données du diagramme sont encodées en Base64, ce qui permet une restauration complète via un seul lien
    En revanche, je ne suis pas certain que cela corresponde vraiment à la définition d’un « state container »

  • Dans mes apps auto-hébergées, j’utilise le hash routing (#/dashboard)
    Cela évite d’avoir besoin de réécriture d’URL côté serveur (.htaccess, etc.), donc même si ce n’est pas parfait, ça réduit les contraintes de déploiement

  • La version récente de Microsoft Teams gère tous les écrans avec une seule URL, donc il est impossible de les mettre en favoris
    On ne peut pas ouvrir directement une équipe ou un canal précis, ce qui est très pénible

  • HATEOAS souffre d’un nom peu engageant, donc le concept n’attire pas l’attention, alors qu’au fond c’est une idée de base du web

    • Du point de vue de l’utilisateur, suivre des liens et soumettre des formulaires, c’est justement HATEOAS
      Mais dans un environnement où l’on contrôle à la fois le serveur et le client, cela n’apporte qu’une complexité supplémentaire
      Surtout si le client doit malgré tout connaître la structure des endpoints : dans ce cas, on ne fait que rendre les URL opaques
    • En réalité, ce sujet n’est pas directement lié à HATEOAS. Les deux utilisent des URL, mais HATEOAS ne concerne pas le stockage d’état ; il s’agit de la structure de navigation
    • C’est une blague, mais au final HATEOAS mériterait plutôt le terme de « cerealization » (format sérialisé)
 
ndrgrd 2025-11-03

J’utilise souvent la mise en veille des onglets, mais avec les web apps qui figent l’URL et fonctionnent comme un seul bloc, les informations disparaissent dès qu’elles passent en veille.

Mais en même temps, ces pages web sont toutes tellement lourdes qu’on ne peut pas non plus se permettre de désactiver la mise en veille.