Use URL Constructor ao invés de template literals para escrever suas URLs
Fala pessoal, hoje eu vim trazer uma dica rápida para vocês que ajudou a tornar meu código mais semântico.
Muitas vezes, trabalhando com backend ou frontend, precisamos fazer algumas requisições com alguns parâmetros, certo?
E eu costumava escrever a URL das minhas requisições dessas forma:
const url = `http://localhost:3000/endpoint?param1=${var1}¶m2=${var2}¶m3=${var3}`
Convenhamos que essa URL é difícil de ler e até de dar manutenção, sempre precisamos identificar o que é parâmetro, o que é variável e o que é apenas a sintaxe do código Javascript.
Para resolver esse problema de semântica, descobri o URL Constructor, que realiza a mesma função que o código acima, porém de uma forma mais eficiente e elegante.
Então, podemos reescrever o mesmo código desta forma:
const url = new URL('http://localhost:3000/endpoint')
url.searchParams.set('param1', var1)
url.searchParams.set('param2', var2)
url.searchParams.set('param3', var3)
O código fala por si só. Na primeira linha, criamos a URL base do endpoint e nas linhas seguintes adicionamos os search params necessários.
Pronto, agora a variável url
contém os mesmos search params que antes, mas agora utilizando a classe URL
, deixando o código mais simples e muito mais fácil de manter.
E você, já tinha utilizado a classe URL
alguma vez? Quem sabe para alguma outra finalidade? Me conta aí.
Muito bom!
Este é um recurso que - minha impressão - poucas pessoas usam no dia-a-dia (infelizmente).
Outro ponto muito importante é que o searchParams
já cuida de vários detalhes chatos pra vc. Por exemplo, se o valor do parâmetro tiver caracteres como &
ou =
, ele já trata corretamente:
const url = new URL('http://localhost:3000/endpoint');
url.searchParams.set('param1', 'a&b=c');
console.log(url.toString()); // http://localhost:3000/endpoint?param1=a%26b%3Dc
Repare que ao converter a URL para string, já é feito automaticamente o URL encoding dos caracteres &
e =
para %26
e %3D
. Assim o valor é enviado corretamente (no caso, o parâmetro param1
com o valor a&b=c
).
Se eu fizesse a concatenação de strings, a URL ficaria http://localhost:3000/endpoint?param1=a&b=c
, ou seja, seriam enviados dois parâmetros (param1
com o valor a
e b
com o valor c
). Para ficar correto, vc teria que fazer a substituição manualmente, mas pra que fazer isso se o searchParams
já cuida disso pra vc?
Outro caso interessante que ele já trata é quando a URL tem anchor, pois este sempre deve ficar no final.
const url = new URL('http://localhost:3000/endpoint#anchor');
url.searchParams.set('param1', 'a');
console.log(url.toString()); // http://localhost:3000/endpoint?param1=a#anchor
console.log(url.searchParams); // URLSearchParams { 'param1' => 'a' }
console.log(url.hash); // #anchor
Ou seja, se vc sempre adicionar os parâmetros no final, ficaria http://localhost:3000/endpoint#anchor?param1=a
. Mas está errado, pois neste caso, ela fica sem nenhum parâmetro, e o anchor é tudo que vem depois do #
, veja:
// ERRADO: adicionar o parâmetro depois do anchor
const url = new URL('http://localhost:3000/endpoint#anchor?param1=a');
console.log(url.searchParams); // URLSearchParams {} (vazio)
console.log(url.hash); // #anchor?param1=a
Além disso, o searchParams
permite fácil acesso aos parâmetros:
const url = new URL('http://localhost:3000/endpoint?param1=a¶m2=b¶m3=c');
// obter um parâmetro específico
console.log(url.searchParams.get('param1')); // a
// loop por todos
for (const [nome, valor] of url.searchParams) {
console.log(`${nome} = ${valor}`);
}
Se pesquisar por aí, vc até vai encontrar "soluções" que envolvem regex ou concatenação de strings. E pode até "funcionar", até o momento em que vc se depara com estes casos especiais. O mais correto e garantido é usar o searchParams
, que já cuida de todos esses casos.
Outra vantagem de se usar o objeto URL
é que dá para separar facilmente os componentes da URL:
const url = new URL('http://user:senha@localhost:3000/endpoint/v1?param1=a¶m2=b#anchor');
console.log(url.protocol); // http:
console.log(url.username); // user
console.log(url.password); // senha
console.log(url.host); // localhost:3000
console.log(url.hostname); // localhost
console.log(url.port); // 3000
console.log(url.pathname); // /endpoint/v1
console.log(url.search); // ?param1=a¶m2=b
console.log(url.hash); // #anchor
Até daria pra fazer uma regex (a "solução" mais comum se vc pesquisar), mas é algo bem propenso a erros, e se torna tão complexo para tratar casos especiais que acaba não valendo a pena.
Por fim, outra vantagem é que o construtor dá erro caso a URL seja inválida (por exemplo, new URL('abc')
lança um TypeError
), ou seja, vc também já garante a validação - o que é mais trabalhoso se for verificar a string manualmente.
Para mais detalhes, consulte a documentação:
Eu faço da primeira forma. Não sei dizer muito bem o motivo, mas me parece mais natural, mais fluido do que a segunda opção. Mas foi bem útil a informação.