Pular para o conteúdo

Arcane.Url

Endereços: ler em partes, montar de volta, resolver relativo e escapar o que precisa ser escapado.

Todo programa que fala HTTP mexe com URL, e a linguagem não tinha onde. O Kiln partia a query string por dentro para entregar req["query"], e o Arcane.Http montava endereço concatenando texto — nada disso estava ao alcance de quem escreve.

dataforge
adopt Arcane.Url as U

p := U.ler("https://loja.com/itens?pagina=2&q=caf%C3%A9#topo")
out p["host"]        // loja.com
out p["query"]       // {pagina: 2, q: café}
out p["porta"]       // void — a URL não disse

Por que não dá para fazer com split#

Dois bugs conhecidos: o ? que também aparece dentro de um valor, e o acento que precisa virar %C3%A9 — e não virava. Escapar à mão erra na primeira busca com espaço.

dataforge
U.escapar("/itens/ação nova")      // /itens/a%C3%A7%C3%A3o%20nova
U.escapar_tudo("/itens/ação")      // %2Fitens%2Fa%C3%A7%C3%A3o
U.desescapar("caf%C3%A9+quente")   // café quente

A chave que repete#

?tag=a&tag=b é legítimo e comum em filtro de busca, e um vault não guarda as duas. query devolve a última (o que quase todo servidor usa) e query_lista devolve as duas — a diferença está escrita, em vez de virar surpresa.

dataforge
p := U.ler("https://a.com/b?tag=a&tag=b")
out p["query"]["tag"]         // b
out p["query_lista"]["tag"]   // [a, b]

Montar, e paginar#

montar é o contrário de ler, e recusa campo que não conhece: caminh montaria um endereço sem caminho, sem nada denunciando. com_query troca um parâmetro e preserva os outros — é o que se faz para paginar —, e void ali apaga o parâmetro, como se tira um filtro.

dataforge
U.montar({"esquema": "https", "host": "a.com", "caminho": "/b",
          "query": {"q": "com espaço", "tags": ["p", "q"]}})
// https://a.com/b?q=com+espa%C3%A7o&tags=p&tags=q

U.com_query("https://a.com/l?pagina=1&q=z", {"pagina": 3})
// https://a.com/l?pagina=3&q=z

U.com_query("https://a.com/l?pagina=1&q=z", {"q": void})
// https://a.com/l?pagina=1

U.juntar("https://a.com/doc/x", "../y")     // https://a.com/y