Elido
7 min de leituraEngenharia

Lançando a migração do TinyURL: REST Pro/Bulk, sem caminho para o plano gratuito

Como criamos importações do TinyURL Pro/Bulk com um clique para o Elido — por que o TinyURL público não tem API, a terminologia alias-vs-slug e o limite que implementamos propositalmente.

Marius Voß
DevRel · edge infra
Diagrama de pipeline: API TinyURL Pro/Bulk à esquerda fluindo através do worker de importação do Elido para a tabela de links, com um painel lateral listando as garantias numéricas (limite de 50k, orçamento de 30 min, 100 por página, apenas planos Pro/Bulk)

A quarta fonte de migração em nosso rollout Tier-3 foi lançada hoje. Cole um token de API TinyURL Pro ou Bulk, escolha um domínio de destino no Elido, clique em Iniciar. Quatro a sete minutos depois, cada alias do TinyURL estará em seu domínio Elido, com o alias preservado onde não houve colisão.

Este post é o relatório técnico — o que é específico do TinyURL, o limite deliberado que implementamos e por que a "migração do plano gratuito do TinyURL" não é algo que possamos construir.

O problema do plano gratuito#

O TinyURL público não tem API e nunca teve. O clássico tinyurl.com/<slug> que você cria sem uma conta é um redirecionamento fire-and-forget — o usuário o cria pelo formulário da página inicial, recebe um slug de volta e o slug nunca reaparece em nenhum painel de conta. Não existe listagem por usuário porque não existe vínculo por usuário.

Isso é bem conhecido, mas vale a pena destacar na página de destino /migrate-from/tinyurl, porque a consulta de pesquisa "migrar do TinyURL" não diferencia o Pro do gratuito. Implementamos:

  • Um aviso claro de "Apenas Pro/Bulk" no hero da página de destino.
  • Uma entrada de FAQ que aponta usuários do plano gratuito para o formulário /docs/guides/bulk-create para encurtamento em massa colando a lista de destinos.
  • Uma etapa de validação de token no inicializador que falha rapidamente com "este token não está em um plano Pro ou Bulk" em vez de deixar a execução silenciosamente retornar 401 durante a paginação.

O raciocínio: todas as outras fontes de migração que lançamos têm um caminho feliz para "todo usuário que a procura". O TinyURL é a exceção — usuários do plano gratuito precisam de um modelo mental diferente e devemos definir essa expectativa antes que eles colem qualquer coisa.

Formato da API REST Pro/Bulk#

A TinyURL Pro API é direta: bearer token, respostas JSON, 100 aliases por página. A paginação usa um parâmetro de query-string page com indexação em 1; a resposta inclui data.aliases (o array de links) e meta.has_more (o sinal de continuação).

const tinyurlPageSize = 100

page := 1
for {
    resp, err := w.fetchPage(ctx, opts.Token, page)
    if err != nil { /* mark failed */ return }
    if len(resp.Data.Aliases) == 0 { break }
    for _, alias := range resp.Data.Aliases { /* import */ }
    if !resp.Meta.HasMore { break }
    page++
}

Cada alias carrega url (o destino longo), alias (o slug personalizado ou código curto gerado automaticamente), description (um campo opcional do TinyURL que preservamos como o título do link no Elido) e um domain (o TinyURL permite domínios personalizados nos planos Bulk).

Terminologia — alias vs slug#

O TinyURL os chama de "aliases". Nós os chamamos de "slugs". A mesma coisa — a sequência de caracteres após o host na URL de redirecionamento. A migração preserva o alias 1:1 onde o domínio Elido de destino não tem colisão; se houver colisão, aplica-se a estratégia padrão de conflito de sufixo/ignorar/falhar.

Consideramos renomear "slug" para "alias" no inicializador para corresponder à terminologia do fornecedor de origem e rejeitamos por razões de consistência. Todas as outras superfícies do Elido — lista de links, API, SDK, painel — usam "slug". Importar a assimetria de terminologia para um inicializador tornaria a experiência pós-importação confusa.

O inicializador exibe um rótulo de uma linha dizendo "O TinyURL chama isso de aliases" acima do botão de rádio da estratégia de conflito, para que usuários procurando por "alias" na página de receita encontrem o controle correto sem ler cada palavra.

Domínios personalizados e a transferência de DNS#

Os planos Bulk do TinyURL suportam domínios personalizados — seu próprio hostname roteando pela infraestrutura do TinyURL. Quando você migra para o Elido, o slug é importado de forma limpa, e o lado do DNS é uma alteração de CNAME.

O caso interessante é "Eu tenho um domínio personalizado no TinyURL Bulk e quero manter o mesmo hostname após a migração". Tratamos isso da mesma forma que a migração do Short.io:

  • A migração é concluída. Os links importados ficam em s.elido.me/<alias> por padrão (ou no seu domínio personalizado do Elido existente).
  • Você adiciona o domínio personalizado do TinyURL como um domínio personalizado do Elido via /docs/guides/custom-domains.
  • Você aponta o CNAME para o Elido. O TLS on-demand do Caddy emite um certificado na primeira solicitação; o domain-manager é a fonte da verdade da lista de permissões, então hostnames não autorizados são rejeitados.
  • A superfície do TinyURL para de resolver para esse hostname; a do Elido assume.

Você pode manter ambas as superfícies vivas em paralelo até que sua assinatura do TinyURL termine, então a transição é apenas deixar o hostname do TinyURL expirar. Sem urgência, sem risco no dia da transição.

O que não migramos#

Histórico de cliques. As análises do TinyURL Pro/Bulk são endpoints de relatório separados que não estão estruturados para exportação. O plano Bulk expõe contagens de cliques por link no painel, mas não os disponibiliza via API amigável para migração; novos cliques caem nas análises do Elido a partir da transição.

Estilização de QR e modelos de UTM do plano Bulk. A mesma história de todas as outras fontes de migração — o slug é importado, a camada de apresentação ao redor é reconstruída no Elido. Marcado como imported:tinyurl para acompanhamento em massa via campanhas.

Links do plano gratuito do TinyURL. Como discutido acima, o TinyURL público não tem API. A mitigação é o formulário de criação em massa, não um job de migração.

Tratamento de tokens#

As mesmas semânticas one-shot do Bitly, Rebrandly e Short.io:

bgCtx := context.WithoutCancel(r.Context())
go h.tinyurl.Run(bgCtx, job.ID, imports.TinyURLJobOptions{
    Token: req.Token,
})

source_token_id permanece NULL. O token vive na memória do processo api-core durante a execução do worker e é descartado na conclusão. Sem persistência, sem linha service_tokens, sem ADR-0036 envelope encryption — esses são para integrações Tier-2 onde o usuário quer chamadas recorrentes ao fornecedor.

A etapa de validação de token no início do job acessa o endpoint /account/domains do TinyURL — uma chamada barata, retorna uma lista de domínios que o token pode ver. Se retornar 401, falhamos rapidamente com "o token é inválido ou não está em um plano Pro/Bulk" em vez de deixar o usuário esperar dois minutos por um 401 no meio da paginação e uma mensagem de erro menos útil.

Resolução de conflito#

Idêntico a todos os outros fornecedores de migração — o sufixo caminha myalias-2, myalias-3, … em caso de colisão; pular deixa o link Elido existente em paz e registra a linha de origem; falhar aborta no primeiro conflito.

func (w *TinyURLWorker) resolveSlug(ctx context.Context, domainID int64, desired, strategy string) (string, error) {
    if _, err := w.links.GetByDomainSlug(ctx, domainID, desired); err != nil {
        if errors.Is(err, pgx.ErrNoRows) { return desired, nil }
        return "", fmt.Errorf("slug lookup: %w", err)
    }
    // suffix/skip/fail branching identical to bitly.go
}

A busca é uma leitura indexada por linha. Pagamos uma leitura extra, mas obtemos caminhos de sufixo determinísticos e mensagens de erro mais amigáveis do que buscar violações de unicidade.

O contrato do worker#

MaxLinksPerImport=50_000, ImportRunBudget=30*time.Minute, progressEvery=50, errorLogCap=1_000. Compartilhado entre todos os cinco fornecedores de migração. Essas constantes são o contrato que a UI de polling do painel assume.

Uma conta TinyURL Pro com 2.000 aliases acessa a API 20 vezes e termina em 3 a 5 minutos. Uma conta Bulk com 20.000 aliases leva 200 viagens de ida e volta e termina em 15 a 20 minutos. Acima de 50.000 aliases, o worker falha severamente com uma instrução para enviar um e-mail para [email protected] para uma migração em partes; o caminho de migração em partes é apenas concierge na v1.

Resumibilidade e o problema de deploy#

A mesma troca que as três primeiras migrações. O worker está em processo; um deploy no meio da importação mata a goroutine. O cron de varredura de travados inverte qualquer linha running sem progresso em 30 minutos para failed. Executar novamente é idempotente sob sufixo e pular.

Para contas com mais de 10.000 aliases, a resumibilidade valeria a pena — gravaríamos o cursor de page do TinyURL em import_jobs.source_filter e retomaríamos da última página concluída. Os outros quatro fornecedores de migração se beneficiarão da mesma mudança assim que a lançarmos; o design é compartilhado.

Fallback para CSV#

Para usuários em planos Bulk com um CSV exportado que não têm mais um token de API ativo, executamos jobs de CSV pontuais da caixa de entrada — envie um e-mail para [email protected]. Não lançamos um formulário de upload de CSV self-service porque o caminho REST cobre o caso comum e o caminho CSV precisa de um ajuste de esquema por conta que é melhor feito manualmente do que por um parser genérico frágil.

O que vem a seguir#

Mais um fornecedor para integrar:

  • Dub.coGET /api/links?projectSlug=…&limit=100. Pastas são achatadas em tags. A API mais limpa das cinco.

Após a Dub, o rollout do Tier-3 está concluído. Cinco integrações de migração, cinco posts de blog de engenharia, um scaffolding de worker compartilhado, uma UI de polling de painel compartilhada.

Se você estava esperando porque a migração do TinyURL não estava documentada, agora está. Experimente — token Pro/Bulk até o último link importado em menos de sete minutos para contas típicas.

Relacionado no blog#

Experimente o Elido

Encurtador de URL hospedado na UE: domínios personalizados, análises profundas e API aberta. Plano gratuito — sem cartão de crédito.

Tags
tinyurl migration
url shortener
go worker
data migration
engineering
tier 3 integrations

Continuar lendo