- A estrutura da URL funciona não apenas como um endereço simples, mas como um meio de armazenar e restaurar o estado da aplicação
- Apresenta o caso da página de download do PrismJS, em que um único URL reproduz completamente as configurações de tema, linguagem e plugins
- Cada componente, como caminho, parâmetros de consulta e fragmento, expressa diferentes estados, como navegação hierárquica, filtragem e navegação no cliente
- Filtros de busca, paginação, modo de visualização e intervalo de datas são adequados para inclusão na URL, enquanto informações sensíveis ou estados temporários da UI não são
- Uma URL bem projetada aumenta a capacidade de compartilhamento, a previsibilidade e a eficiência de cache, reforçando a confiabilidade e a experiência do usuário em aplicações web
O potencial da URL
- A URL não é apenas o endereço de um recurso, mas também funciona como interface do usuário (UI) e contêiner de estado
- Ela preserva automaticamente o estado em compartilhamentos, favoritos, histórico do navegador e deep links
- Desde 1991, atua como o mecanismo básico de gerenciamento de estado da web
- Cada componente da URL representa um tipo diferente de estado
- Caminho (Path): navegação hierárquica de recursos (
/users/123/posts)
- Consulta (Query): filtros, opções e configurações (
?theme=dark&lang=en)
- Fragmento (Fragment): posição dentro do documento ou roteamento SPA (
#features, #/dashboard)
- O recurso Text Fragments permite ligar diretamente a um texto específico dentro da página
Padrões de parâmetros de consulta
- Forma de colocar vários valores em uma única chave usando delimitador (
?tags=frontend,react,hooks)
- Serialização de dados aninhados em JSON ou Base64 (
?config=eyJyaWNrIjoicm9sbCJ9==)
- Flags booleanas expressas pela presença da chave (
?mobile)
- A notação de colchetes (bracket notation) expressa múltiplos valores no formato
tags[]=frontend&tags[]=react
- É reconhecida automaticamente por
qs do Node ou middlewares do Express, por exemplo, mas não é padronizada
- O ponto principal é manter consistência
Exemplos de representação de estado por URL
- PrismJS: armazena toda a configuração de tema, linguagem e plugins no hash da URL
- GitHub: destaca um intervalo específico de linhas de código com
#L108-L136
- Google Maps: inclui coordenadas, nível de zoom e tipo de mapa na URL
- Figma: compartilha o contexto de trabalho, como posição da tela, zoom e elementos selecionados, por URL
- Sites de e-commerce: incluem filtros, ordenação e faixa de preço na URL para restaurar o estado da busca
Padrões de engenharia de frontend
- Estados adequados para inclusão na URL
- termo de busca, filtros, página e ordenação, modo de visualização, intervalo de datas, aba ativa, configuração da UI, flags de funcionalidade
- Estados inadequados para a URL
- informações sensíveis como senhas e tokens, estado temporário da UI, entradas não salvas, dados muito grandes, estados de alta frequência
- Critério de decisão: outro usuário deve ver o mesmo estado ao clicar na mesma URL?
Implementação em JavaScript
- A API
URLSearchParams permite ler e escrever parâmetros de consulta
pushState adiciona um novo item ao histórico, e replaceState atualiza o item atual
- O evento
popstate restaura a UI ao usar o botão de voltar do navegador
Implementação em React
- O hook
useSearchParams do React Router permite gerenciar o estado da URL de forma concisa
- Ao ler e atualizar parâmetros, a URL e a UI são sincronizadas automaticamente
Boas práticas de gerenciamento de estado por URL
- Não incluir valores padrão na URL (manter apenas
?theme=dark; o valor padrão é tratado no código)
- Usar debouncing para evitar atualizações excessivas da URL durante a digitação (com
lodash.debounce)
- pushState vs replaceState
pushState: para estados reversíveis, como alteração de filtros ou navegação entre páginas
replaceState: para ajustes finos, como entrada de busca
Ver a URL como um contrato (Contract)
- Uma URL bem projetada atua como um contrato explícito entre a aplicação e o usuário
- Ela deixa claras as fronteiras entre estados públicos/privados, cliente/servidor e compartilhados/de sessão
- URLs legíveis explicam a intenção e podem ser entendidas tanto por pessoas quanto por máquinas
- Um formato como
example.com/products/laptop?color=silver&sort=price transmite bem o significado
- Melhora da eficiência de cache
- A mesma URL é tratada como o mesmo recurso, aumentando a taxa de acerto do cache
- Parâmetros de consulta podem controlar variações de cache
- Controle de versão e experimentos
?v=2, ?beta=true, ?experiment=new-ui distinguem versões de API e testes A/B
Antipadrões a evitar
- Manter estado apenas em memória em SPAs, perdendo o estado ao recarregar a página
- Incluir informações sensíveis na URL (
?password=secret123)
- Nomes de parâmetros pouco claros (
?foo=true&bar=2 em vez de ?mobile=true&page=2)
- Codificar JSON complexo em Base64, gerando URLs longas demais
- Ultrapassar o limite de tamanho da URL (há restrições em navegadores, servidores e CDNs)
- Neutralizar o botão de voltar (isso acontece com uso excessivo de
replaceState)
Conclusão
- Uma boa URL vai além de apontar conteúdo; ela expressa a conversa entre o usuário e a aplicação
- A URL é um dos meios mais antigos e elegantes de gerenciamento de estado, carregando intenção, contexto e capacidade de compartilhamento
- Embora existam ferramentas complexas de gerenciamento de estado como Redux, MobX, Zustand e Recoil,
não esquecer a funcionalidade básica chamada URL é a verdadeira força da web
- Um app que perde estado ao recarregar está deixando passar uma característica essencial da web
2 comentários
Comentários do Hacker News
Durante code review, tento armazenar o máximo possível de estado (state) na URL
Ser levado para um lugar completamente diferente após recarregar a página, ou ver uma tela nada a ver ao abrir uma URL compartilhada, é algo ofensivo do ponto de vista do usuário
Essa abordagem desacelera o desenvolvimento, mas aumenta a percepção de UX dentro da equipe e deixa claro quanto estado estamos colocando na view
Também existe a preocupação de que a URL vire uma espécie de API pública, criando restrições, mas acho que isso não é um grande problema, já que a maioria das URLs só é usada no curto prazo
Se necessário, isso pode ser resolvido com código para migrar a URL antiga para a nova no carregamento
Acho que usar query parameters em vez do path funciona um pouco melhor
Do ponto de vista do usuário, a palavra “voltar” está associada ao botão do navegador, então isso gera confusão
Ter o estado reiniciado ao recarregar incomoda menos, porque existe a noção de que “recarregar = começar de novo”
Quando tudo é feito em JS, esses recursos básicos acabam quebrando de forma sutil
Mas, mesmo tendo trabalhado com mais de 30 designers de UX até hoje, nunca recebi orientação sobre URL
Principalmente no mobile, é difícil voltar a página ao estado inicial, então recarregar vira a solução mais rápida
Em interfaces com rolagem infinita ou filtros complexos, quanto mais estado houver na URL, mais chato fica resetar tudo
Se o usuário já está insatisfeito com a UX e ainda precisa arrumar a URL, isso vira estresse em dobro
Sinto que até pessoas com alta alfabetização digital têm pouca compreensão de URL e DNS
Elas deveriam ser capazes de reduzir o risco de phishing, entender o significado de parâmetros de URL (
?t=_,utm_) e remover informações pessoais antes de compartilharTambém deveriam saber que o cadeado do HTTPS não significa ‘confiável’
Usar a URL como contêiner de estado faz com que a estrutura interna fique exposta e exige versionamento
Também pode causar problemas de compatibilidade entre navegadores ou nos fluxos de autenticação
Mesmo assim, tento expor o máximo de estado possível na URL, como se fossem argumentos de linha de comando
Só que isso é um trade-off intencional, não resultado de ignorância ou falta de experiência
Recomendo a biblioteca antiga, mas ainda útil, Rison
Ela permite armazenar JSON na URL de forma organizada, e também é usada no Kibana da Elastic
Exemplo: http://example.com/service?query=q:'*',start:10,count:10
À medida que o sistema evolui, a estrutura do estado também muda, então colocar estado na URL acaba limitando essa evolução
Isso acontece porque a URL é, por natureza, uma string permanente
Em vez disso, acho mais adequado tratar a URL como uma espécie de protocolo, usando formas de codificar e decodificar o estado
Em páginas simples, até dá para colocar o estado inteiro na URL
Mas, em casos como feeds, isso depende da expectativa do usuário, como “ao recarregar, deve voltar ao estado mais recente?”
O limite de tamanho da URL varia conforme navegador, servidor, CDN e configuração de mecanismo de busca, mas em geral fica abaixo de 2000 caracteres
Fico pensando quanto estado dá para colocar dentro desse limite, ou se seria preciso outra abordagem
- . _ ~), então a densidade de informação é bem altaO draw.io consegue armazenar o estado inteiro na URL para compartilhamento
Os dados do diagrama são codificados em Base64, permitindo restauração completa com um único link
Só não tenho certeza se isso se encaixa na definição de ‘state container’
Eu uso hash routing (#/dashboard) em apps self-hosted
Como não exige reescrita de URL no servidor (.htaccess etc.), isso reduz as restrições do ambiente de deploy, mesmo não sendo perfeito
O Microsoft Teams mais recente trata todas as telas com uma única URL, então é impossível favoritar
É muito inconveniente não conseguir abrir diretamente um time ou canal específico
HATEOAS não chama muita atenção porque o nome não ajuda, mas no fim das contas é um conceito básico da web
Mas, em ambientes em que você controla tanto o servidor quanto o cliente, isso só adiciona complexidade extra
Principalmente se o cliente ainda precisa conhecer a estrutura dos endpoints, isso só torna a URL opaca
Eu uso bastante o recurso de suspensão de abas, mas em webapps que fixam tudo em uma única URL e se movem como um bloco só, quando entram em suspensão as informações se perdem.
Ao mesmo tempo, essas páginas são todas pesadas, então também não dá para simplesmente desativar a suspensão.