Encurtar uma URL em JavaScript é um HTTP POST. Você envia o link longo para a API de um encurtador com fetch, passa sua chave de API como um token Bearer e lê o link curto da resposta JSON. Desde o Node 18, não é preciso instalar nenhum pacote - fetch é global.
O ponto importante é onde esse código é executado. A chave de API de um encurtador é uma credencial que permite consumir cota, e o JavaScript do cliente é público, então o navegador está fora de questão. Tudo abaixo é executado no lado do servidor: um script Node, um route handler ou uma função serverless.
Esta é a versão em JavaScript do guia geral sobre como encurtar uma URL, que aborda o painel e o fluxo pelo navegador. Se você ainda não escolheu um serviço, a visão geral da API gratuita de encurtador de URL apresenta o formato da requisição, o modelo de autenticação e os limites do plano gratuito considerados neste artigo. Os nomes dos campos abaixo são os do Elido, mas o formato - enviar um destino por POST e receber uma URL curta - funciona na maioria dos encurtadores modernos.
A Maneira Mais Rápida: Uma Chamada fetch no Node
Coloque a chave em uma variável de ambiente e envie o destino por POST para o endpoint de links:
const res = await fetch("https://api.elido.app/v1/links", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ELIDO_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
destination_url: "https://example.com/spring-sale?utm_source=newsletter",
}),
signal: AbortSignal.timeout(10_000),
});
if (!res.ok) throw new Error(`shorten failed: ${res.status}`);
const { short_url } = await res.json();
console.log(short_url); // -> https://s.elido.me/ab12cd
Execute com node --env-file=.env shorten.js e a chave nunca toca no código-fonte.
A linha if (!res.ok) não é decoração. fetch só rejeita em caso de falha de rede ou aborto, então um 401 ou 500 retorna como uma promise perfeitamente resolvida com ok: false. Ignore a verificação e uma chave revogada parecerá exatamente um sucesso até que algo mais adiante tente usar undefined como link. Quem vem do axios costuma cair nessa armadilha uma vez.
AbortSignal.timeout é o outro hábito que vale a pena criar. Sem ele, uma conexão travada bloqueia até que o socket morra sozinho, o que em um cron job significa que o job simplesmente desapareceu.
Por Que o Navegador É o Lugar Errado para Isso
Cole esse trecho em um componente React e duas coisas quebram. A primeira é CORS: uma API autenticada por chave não envia Access-Control-Allow-Origin para sites arbitrários, então o navegador bloqueia a resposta. Ler a referência de CORS da MDN geralmente faz as pessoas procurarem um proxy que elimine o erro.
O erro é o sintoma. O problema real é o segundo: qualquer pessoa que abra o DevTools ou use grep no bundle consegue ler uma chave no código do front-end. Os bundlers não a escondem, os prefixos NEXT_PUBLIC_ a anunciam, e uma chave pública em uma API paga é cota gratuita de outra pessoa.
O formato que funciona coloca uma rota sua no meio. O navegador envia uma URL simples para seu próprio endpoint, o servidor adiciona a chave e ela permanece em uma variável de ambiente que o cliente nunca vê:
// app/api/shorten/route.js (Next.js App Router)
export async function POST(request) {
const { url } = await request.json();
const res = await fetch("https://api.elido.app/v1/links", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ELIDO_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ destination_url: url }),
});
const { short_url } = await res.json();
return Response.json({ short_url });
}
Valide url antes de encaminhá-la. Um endpoint aberto que encurta qualquer coisa enviada por qualquer pessoa é um redirecionamento aberto com etapas extras, e o artigo sobre redirecionamentos abertos explica o que os invasores fazem com um deles.
Adicione um Timeout, Novas Tentativas e uma Chave de Idempotência
O caminho feliz tem oito linhas. Um job executado sem supervisão precisa sobreviver a um 429, a um 5xx temporário e ao caso mais complicado em que o POST é bem-sucedido, mas a resposta nunca chega: seu código atinge o timeout, tenta novamente e agora há dois links curtos para um destino.
Uma chave de idempotência fecha essa lacuna. Gere uma por URL, reutilize-a em cada nova tentativa daquela URL e a API devolverá o link original em vez de criar um segundo.
import { randomUUID } from "node:crypto";
const API = "https://api.elido.app/v1/links";
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
export async function shorten(destinationUrl, { retries = 3 } = {}) {
const idempotencyKey = randomUUID(); // one per URL, not per attempt
for (let attempt = 0; attempt < retries; attempt++) {
const res = await fetch(API, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ELIDO_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": idempotencyKey,
},
body: JSON.stringify({ destination_url: destinationUrl }),
signal: AbortSignal.timeout(10_000),
});
if (res.status === 429) {
await sleep(Number(res.headers.get("Retry-After") ?? 2) * 1000);
continue;
}
if (res.status >= 500) {
await sleep(2 ** attempt * 1000); // exponential backoff
continue;
}
if (!res.ok) {
throw new Error(`shorten failed: ${res.status} ${await res.text()}`);
}
return (await res.json()).short_url;
}
throw new Error(`shorten failed after ${retries} attempts`);
}
Um 401 ou 403 nunca se corrigirá sozinho, então esses erros são lançados imediatamente, sem consumir três tentativas. Um 429 espera exatamente o tempo solicitado pelo cabeçalho Retry-After. Somente 5xx recebe backoff exponencial. O aprofundamento sobre limites de taxa e idempotência explica por que um loop ingênuo de novas tentativas transforma a indisponibilidade de um fornecedor em dois links.
Quer executar os trechos exatamente como estão? Crie uma chave no plano gratuito, exporte-a como ELIDO_API_KEY e todos os exemplos desta página funcionarão sem alterações.
Encurte URLs em Massa sem Esbarrar no Limite de Taxa
A versão óbvia para várias URLs é Promise.all(urls.map(shorten)). Ela dispara todas as requisições no mesmo instante, então uma lista de 500 URLs vira 500 conexões simultâneas e a API responde à maioria com 429. Um pool pequeno resolve isso: um número fixo de workers retirando itens de uma fila compartilhada, para que a concorrência permaneça constante, independentemente do tamanho da lista.
export async function shortenAll(urls, concurrency = 8) {
const queue = [...urls];
const results = new Map();
const worker = async () => {
while (queue.length) {
const url = queue.pop();
try {
results.set(url, await shorten(url));
} catch (err) {
results.set(url, `ERROR: ${err.message}`); // one bad URL must not sink the batch
}
}
};
await Promise.all(Array.from({ length: concurrency }, worker));
return results;
}
Associar os resultados à URL original faz com que uma falha parcial fique visível e possa ser executada novamente, em vez de se tornar uma lacuna silenciosa na saída. Defina concurrency conforme a documentação do plano; oito é um ponto de partida seguro, e os cabeçalhos da resposta informam quando é hora de reduzir esse número.
Se preferir não manter nada disso, a API e os SDKs já trazem a lógica de novas tentativas e paginação conectada, e o início rápido dos SDKs mostra a versão tipada da mesma chamada.
Onde o Código Deve Ficar
Quatro lugares cobrem quase tudo. Um script pontual que encurta um CSV funciona bem como Node puro com --env-file. Um formulário no seu site precisa do route handler acima, com a chave no servidor e o navegador falando apenas com você. Um worker de fila é adequado para um lote grande o suficiente para que nenhuma requisição HTTP deva esperar por ele. E uma etapa de build que gera links de campanha pertence à CI, com a chave como um segredo do repositório.
Uma ressalva sobre runtimes edge: node:crypto não está disponível neles, mas crypto.randomUUID() é um global do Web Crypto no Vercel Edge, Cloudflare Workers e Deno, então troque o import e o restante do código não muda.
O lugar muda, mas a lista de verificação não: chave no ambiente, timeout em toda requisição, leitura de res.ok antes do corpo e uma chave de idempotência em qualquer operação que possa ser executada duas vezes. Equipes que fazem isso em escala normalmente acabam lendo o que mais a API oferece - cliques, tags e expiração - e configurando webhooks para eventos de links em vez de consultar a API repetidamente.
Leia a Série Cornerstone
Este artigo faz parte do cluster de engineering. Comece com o guia da API gratuita de encurtador de URL para entender o endpoint e a autenticação, depois leia o artigo sobre limites de taxa e idempotência para agir corretamente sob carga. A referência atualizada está na documentação da API, e encurtadores de URL para desenvolvedores explica o que procurar em uma API antes de escolhê-la.
Relacionados no Blog
- Como encurtar uma URL em Python com a biblioteca requests
- Como encurtar uma URL em PHP com curl, Guzzle e WordPress
- Como encurtar uma URL em Go com net/http
- API gratuita de encurtador de URL: formato da requisição, autenticação e limites
- Como encurtar uma URL em Java com o HttpClient integrado
- Como encurtar uma URL em C# com HttpClient e .NET
Perguntas frequentes
Como encurto uma URL em JavaScript?
Envie um HTTP POST para a API de um encurtador de URLs com fetch, passando a URL longa no corpo JSON e sua chave de API como um token Bearer, e depois leia o link curto da resposta analisada. No Node 18 ou mais recente, fetch já vem integrado, então não é preciso instalar nenhum pacote: monte os cabeçalhos, envie a URL de destino para o endpoint de links e use o campo short_url do JSON recebido.
Posso encurtar uma URL no navegador com JavaScript?
Não com sua chave de API na página. Qualquer coisa no JavaScript do cliente pode ser lida no DevTools, então uma chave enviada ao navegador é uma chave pública que qualquer pessoa pode usar para consumir sua cota. Chame o encurtador a partir de uma rota de servidor ou de uma função serverless e faça o navegador chamar essa rota.
Por que minha requisição fetch para um encurtador de URLs retorna um erro de CORS?
Porque a API do encurtador não envia um cabeçalho Access-Control-Allow-Origin para o seu site, o que é intencional em um endpoint autenticado por chave. O navegador bloqueia a resposta mesmo que a requisição possa ter sido bem-sucedida. Mover a chamada para o lado do servidor tira o navegador do caminho e elimina o erro.
Preciso de um pacote npm para encurtar URLs no Node.js?
Não. O Node oferece fetch global a partir da versão 18, e uma chamada à API de um encurtador é um POST com dois cabeçalhos, então uma dependência acrescenta muito pouco. Recorra a um SDK quando quiser respostas tipadas, novas tentativas integradas e auxiliares de paginação em muitos endpoints, em vez de uma única chamada.
Como encurto muitas URLs de uma vez no Node.js?
Execute um pequeno pool de workers em vez de usar Promise.all sobre a lista inteira, para que apenas algumas requisições estejam em andamento a cada momento e você fique abaixo do limite de taxa. Envie um Idempotency-Key por URL para que uma requisição repetida devolva o link original em vez de criar uma duplicata.
fetch lança um erro em uma resposta 401 ou 500?
Não, e isso confunde quem vem do axios. fetch só rejeita em caso de falha de rede ou de uma requisição abortada, então um 401 ou 500 chega como uma resposta resolvida com ok definido como false. Verifique response.ok por conta própria antes de ler o corpo, ou uma chamada que falhou parecerá bem-sucedida.
Experimente Elido
Cole uma URL, obtenha um link curto
Sem cadastro. O link vive 30 dias. Cadastre-se para mantê-lo para sempre.
Grátis, sem necessidade de registo · 2 por dia