<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Marco Ollivier</title>
    <description>The latest articles on Forem by Marco Ollivier (@marcopollivier).</description>
    <link>https://forem.com/marcopollivier</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F324753%2F57cdfb7a-38d3-4007-a5ef-4cf4dec8c0eb.jpeg</url>
      <title>Forem: Marco Ollivier</title>
      <link>https://forem.com/marcopollivier</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/marcopollivier"/>
    <language>en</language>
    <item>
      <title>Como resolver um "Failed to Download Module" do Terraform / OpenTofu</title>
      <dc:creator>Marco Ollivier</dc:creator>
      <pubDate>Sat, 18 May 2024 00:40:17 +0000</pubDate>
      <link>https://forem.com/marcopollivier/como-resolver-um-failed-to-download-module-do-terraform-opentofu-5cha</link>
      <guid>https://forem.com/marcopollivier/como-resolver-um-failed-to-download-module-do-terraform-opentofu-5cha</guid>
      <description>&lt;h2&gt;
  
  
  Do nada as coisas quebram
&lt;/h2&gt;

&lt;p&gt;Eu rodo quase que diariamente o meu projeto principal de infra da empresa e tudo funciona super bem. &lt;/p&gt;

&lt;p&gt;Eis que um belo dia... talvez não a toa... numa sexta feita no final do expediente um módulo simplesmente deixa de responder e apresenta o erro &lt;code&gt;Error: Failed to download module&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Provavelmente você tá muito identificado nesse momento. Aposto que isso já aconteceu com você em algum momento. Nem precisa ser com Terraform. &lt;/p&gt;

&lt;p&gt;Pois é. Aconteceu comigo. Do nada, ao rodar o meu &lt;code&gt;tofu init&lt;/code&gt;, meu módulo do Aurora parou de responder&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Initializing the backend...
Initializing modules...
Downloading registry.opentofu.org/terraform-aws-modules/rds-aurora/aws 9.3.1 for global.aurora.xxx_rds_aurora...
╷
│ Error: Failed to download module
│
│   on global/aurora/aurora.tf line 1:
│    1: module "xxx_rds_aurora" {
│
│ Could not download module "xxx_rds_aurora" (global/aurora/aurora.tf:1) source code from "git::https://github.com/terraform-aws-modules/terraform-aws-rds-aurora?ref=v9.3.1": error downloading
│ 'https://github.com/terraform-aws-modules/terraform-aws-rds-aurora?ref=v9.3.1': /opt/homebrew/bin/git exited with 128: Cloning into '.terraform/modules/global.aurora.xxx_rds_aurora'...
│ ssh: Could not resolve hostname github.comterraform-aws-modules: nodename nor servname provided, or not known
│ fatal: Could not read from remote repository.
│
│ Please make sure you have the correct access rights
│ and the repository exists.
│ .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Investigação
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Obvio que a AI não me ajudou
&lt;/h3&gt;

&lt;p&gt;E agora o que fazer? &lt;/p&gt;

&lt;p&gt;No Novo Mundo das AIs a primeira reação é perguntar pro ChatGPT. Foi o que eu fiz. Eu nem li o erro direito. &lt;/p&gt;

&lt;p&gt;E é óbvio que ele me deu uma pá de soluções que nem fazia sentido. &lt;/p&gt;

&lt;h3&gt;
  
  
  Por que eu não li o erro desde o começo?
&lt;/h3&gt;

&lt;p&gt;Fiz os checks básicos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Leu o erro? Agora sim!&lt;/li&gt;
&lt;li&gt;O modulo ainda existe? Sim!&lt;/li&gt;
&lt;li&gt;A versão existe? Sim! &lt;/li&gt;
&lt;li&gt;Eu mudei alguma coisa? Não!&lt;/li&gt;
&lt;li&gt;Alguém mudou alguma coisa? Não! &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Então por que diabos ele não tá achando? &lt;/p&gt;

&lt;p&gt;O erro fala sobre download... e tava mais obvio do que eu poderia imaginar&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Could not download module "xxx_rds_aurora" (global/aurora/aurora.tf:1) source code 
from "git::https://github.com/terraform-aws-modules/terraform-aws-rds-aurora?ref=v9.3.1": error downloading
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Foi quando eu me dei conta: ele está tentando baixar o módulo via &lt;code&gt;https&lt;/code&gt; só que meu git está configurado pra baixar via &lt;code&gt;ssh&lt;/code&gt;. Obvio que vai dar ruim. &lt;/p&gt;

&lt;p&gt;A partir daqui vai o checklist seguinte: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Meu &lt;code&gt;~/.gitconfig&lt;/code&gt; está configurado corretamente? Sim!
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[url "ssh://git@github.com/"]
    insteadOf = https://github.com/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A configuração de usar o ssh em vez do https está ativa. &lt;/p&gt;

&lt;p&gt;Bom. Só sobrou a nível de Terraform e OpenTofu. &lt;/p&gt;

&lt;p&gt;E realmente era o que faltava. &lt;/p&gt;

&lt;h2&gt;
  
  
  Solução
&lt;/h2&gt;

&lt;p&gt;Não sei exatamente o motivo disso ter mudado do nada. Eu realmente não fiz nenhum tipo de alteração no meu ambiente de trabalho. &lt;/p&gt;

&lt;p&gt;Mas a solução é simples. Se você ainda não tem um arquivo &lt;code&gt;~/.terraformrc&lt;/code&gt; ou &lt;code&gt;~/.opentofurc&lt;/code&gt; crie... e adicione um &lt;code&gt;provider mirror&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;provider_installation {
  network_mirror {
    url = "ssh://git@github.com/"
    match = "github.com"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso vai evitar que você não consiga baixar os módulos por causa do seu Github. &lt;/p&gt;

&lt;p&gt;E, crianças... leiam os erros e as documentações. Isso vai ser um diferencial em relação a carreira de vocês. &lt;/p&gt;

</description>
      <category>terraform</category>
      <category>opentofu</category>
      <category>infraascode</category>
    </item>
    <item>
      <title>Pratique com APIs de verdade - ClimaTempo</title>
      <dc:creator>Marco Ollivier</dc:creator>
      <pubDate>Thu, 10 Aug 2023 01:25:18 +0000</pubDate>
      <link>https://forem.com/marcopollivier/pratique-com-apis-de-verdade-climatempo-9c7</link>
      <guid>https://forem.com/marcopollivier/pratique-com-apis-de-verdade-climatempo-9c7</guid>
      <description>&lt;p&gt;Já aconteceu mais de uma vez de pessoas que estão começando me pedirem dicas de projetos para começar. Ainda nessa questão de pedir dicas, também já me perguntaram como poderia praticar consumir APIs em projetos backend para terem a sensação que estão construindo algo que faça sentido e não algo que eles mesmos inventaram. &lt;/p&gt;

&lt;p&gt;Um tempo atrás, eu fui apresentado ao &lt;a href="https://www.themoviedb.org/about" rel="noopener noreferrer"&gt;TMDB&lt;/a&gt; (The Movie DB), que é basicamente um serviço online criado e mantido pela comunidade e que você consegue consumir informações referentes a filmes e series. Esse serviço já é excepcional pro nosso propósito e, francamente, já usei algumas vezes pra praticar com novos frameworks e ter um resultado mais agradável e até mesmo mais real. Só que... ainda é uma coisa meio como se eu mesmo tivesse feito. Não tem aquela sensação boa de aplicação real e prática. &lt;/p&gt;

&lt;p&gt;Foi quando, navegando pela internet esses dias, eu descobri que o ClimaTempo tem uma API que te dá resultados reais sobre clima e tempo (sem trocadilhos com o nome). E você encontra essa API no endereço &lt;a href="https://advisor.climatempo.com.br/" rel="noopener noreferrer"&gt;https://advisor.climatempo.com.br/&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  A API ClimaTempo
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A API em números
&lt;/h3&gt;

&lt;p&gt;Eles oferecem um serviço que dispõe de uma versão free (obviamente com algumas limitações) e prometem ter um uptime de 99,8%. O que considero um valor bem satisfatório. &lt;/p&gt;

&lt;p&gt;Além disso, também fornecem uma documentação bem interessante e bem explicada da sua API que será fornecida usando o modelo REST. &lt;/p&gt;

&lt;p&gt;Também oferecem um dashboard bem interessante que te ajuda a acompanhar o quanto você está dentro do seu plano. &lt;/p&gt;

&lt;h3&gt;
  
  
  O Dashboard
&lt;/h3&gt;

&lt;p&gt;Quando você cria sua conta, uma das primeiras coisas que você vai ter acesso é ao Board. Que vai te ajudar a ver informações sobre o status da API, o uptime, o tempo médio de resposta e quantos hits/dia você já vez. &lt;/p&gt;

&lt;p&gt;Lembrando que o plano free te oferece um limite de 10req/min ou 100req/dia. Mais do que suficiente. &lt;/p&gt;

&lt;h3&gt;
  
  
  A Documentação
&lt;/h3&gt;

&lt;p&gt;A documentação não foge muito do padrão e você pode encontrar &lt;a href="http://apiadvisor.climatempo.com.br/doc/index.html" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;. Mas como a forma com que modelamos uma API reflete muito na doc, aqui vale ressaltar que considero o contrato que foi desenhado nessa API bem interessante e que pode servir de inspiração caso você esteja criando uma do zero e esteja com algumas dúvidas sobre como estruturar. &lt;/p&gt;

&lt;p&gt;Aqui pegamos o gancho para seu token de acesso. Todos (os que eu vi, ao menos) endpoints vão pedir para você passar seu token como query parameter. &lt;/p&gt;

&lt;p&gt;Aqui uma opinião pessoal: acho estranho passar o token dessa forma. Eu optaria por passar via header, mas tudo bem. &lt;/p&gt;

&lt;p&gt;E esse token você consegue gerar um novo com muita facilidade no painel. &lt;/p&gt;

&lt;p&gt;Também é outro ponto que eu talvez mudasse. Esse modelo de token é um pouco inseguro, pois em caso de vazamento, ele não é gerado novamente depois de x minutos. O que pode ser um problema, mas como aqui não estamos falando de dados sensíveis, também não é o fim do mundo. Você só teria indisponibilidade por atingir o máximo de acessos diários. &lt;/p&gt;

&lt;h2&gt;
  
  
  Colocando em prática
&lt;/h2&gt;

&lt;p&gt;Pra esse post não ficar apenas na pegada de textão, vamos fazer uma integração simples usando Go da forma mais básica possível?&lt;/p&gt;

&lt;p&gt;Vamos começar criando um projeto e para isso, vou usar toda a minha criatividade de dev para nomear coisas e criar uma pasta chamada &lt;code&gt;climatempo-go&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir climatempo-go
$ go mod init github.com/marcopollivier/climatempo-go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para esse projeto eu estou usando ainda a versão 1.20 (a 21 saiu ontem... dá o desconto) &lt;/p&gt;

&lt;p&gt;E aqui pra esse primeiro post, eu vou simplesmente criar um &lt;code&gt;main.go&lt;/code&gt; e fazer tudo dentro dele. Eu coloquei ali nas tags que era pra iniciante, então não reclama. Vou tentar fazer outros posts avançando com esse projeto. &lt;/p&gt;

&lt;p&gt;Vamos de Hello, world pra ver se tá tudo bem com meu ambiente. Eu SEMPRE faço isso.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Oi, mundo"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como eu vou usar o pacote &lt;code&gt;net/http&lt;/code&gt; vamos de &lt;a href="https://pkg.go.dev/net/http" rel="noopener noreferrer"&gt;documentação&lt;/a&gt; ou de &lt;a href="https://gobyexample.com/http-client" rel="noopener noreferrer"&gt;go by example&lt;/a&gt; pra ter certeza que nada mudou. &lt;/p&gt;

&lt;p&gt;Ah... aqui, como nós vamos pegar uma informação de algum lugar, nós vamos ser considerados clientes, se pensarmos em uma estrutura cliente/servidor. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Se você tiver dúvidas em relação a isso, pense: eu estou pedindo ou servindo... acho que agora ficou claro, certo? &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Bom. Vamos de condições atuais do tempo. Você vai encontrar essa parte aqui nesse endereço da documentação: &lt;a href="http://apiadvisor.climatempo.com.br/doc/index.html#api-Weather-CurrentWeatherByCity" rel="noopener noreferrer"&gt;http://apiadvisor.climatempo.com.br/doc/index.html#api-Weather-CurrentWeatherByCity&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E de acordo com ela, faremos um &lt;code&gt;GET&lt;/code&gt; no endpoint &lt;code&gt;/api/v1/weather/locale/:id/current?token=your-app-token&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;O que, no fim, ficaria algo parecido com isso aqui, caso chamássemos via terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-i&lt;/span&gt; http://apiadvisor.climatempo.com.br/api/v1/weather/locale/3477/current?token&lt;span class="o"&gt;=&lt;/span&gt;your-app-token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Traduzindo isso para código Go, teríamos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"net/http"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://apiadvisor.climatempo.com.br/api/v1/weather/locale/3477/current?token=your-app-token"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mas isso ainda não faz nada... quer dizer... esse Get até acontece, mas não pegamos essa informação e criamos alguma coisa com ela. &lt;/p&gt;

&lt;p&gt;Aqui vale um passo atrás e mostrar que não tirei nada da minha cabeça. Eu sei que você já clicou e viu a documentação que mandei ali em cima, mas caso o texto tenha envolvido tanto você que fez você perder essa oportunidade, você vai perceber algumas coisas na documentação. &lt;/p&gt;

&lt;p&gt;Ela vai ser composta por:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;o contrato (endereço e método HTTP) &lt;/li&gt;
&lt;li&gt;um exemplo de como fica esse contrato (usando o curl por padrão) &lt;/li&gt;
&lt;li&gt;os parâmetros que você precisa passar. &lt;/li&gt;
&lt;li&gt;O que essa API vai retornar quando tiver em um cenário de sucesso&lt;/li&gt;
&lt;li&gt;E o que ela vai retornar em um cenário de erro.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;E o nosso código vai precisar representar cada uma dessas informações. Vamos ver isso acontecer? &lt;/p&gt;

&lt;h3&gt;
  
  
  O contrato
&lt;/h3&gt;

&lt;p&gt;Vamos começar por essa parte do nosso contrato. Onde tempos os 3 primeiros items dessa lista acima. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5sk1gtf5lgncbzh2xu02.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5sk1gtf5lgncbzh2xu02.png" alt="Contrato da api do Climatempo" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E vamos fazer essa correlação com o código que estamos criando. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff5ubgc8bid4lpptkw3n4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff5ubgc8bid4lpptkw3n4.png" alt="Correlação entre código e documentação da API do ClimaTempo" width="800" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffeg5vvr203kuu8xr5kis.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffeg5vvr203kuu8xr5kis.png" alt="E aqui os parametros" width="800" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dessa forma, vamos evoluir nosso código da seguinte forma.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"bufio"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://apiadvisor.climatempo.com.br/api/v1/weather/locale/3477/current?token=your-app-token"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;scanner&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;bufio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewScanner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;scanner&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scan&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scanner&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dando uma resumida no que esse código está fazendo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ele pega a resposta desse Get e atribui o valor pra variável &lt;code&gt;resp&lt;/code&gt;. Como essa função http.Get tem um retorno multivalorado, o segundo parâmetro seria um erro, mas pra esse exemplo não quero me preocupar com isso. De modo que uso &lt;code&gt;_&lt;/code&gt;(underline) para dizer que não quero fazer nada com esse retorno. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Um disclaimer sobre o underline: esse aqui é um exemplo meramente didático pra falarmos sobre o processo básico de consumir uma API. Evite ao máximo usar isso em um código que vá para o ambiente produtivo, especialmente se for um retorno de erro como era esse caso. &lt;/p&gt;

&lt;p&gt;Logo depois de pegar o retorno, eu chamo um &lt;code&gt;defer&lt;/code&gt; que vai chamar a função de &lt;code&gt;Body.Close()&lt;/code&gt; e colocar no final da pilha de execuções. Dessa forma depois de executar tudo que está previsto nessa função, ele vai fechar essa conexão da chamada. &lt;/p&gt;

&lt;p&gt;Depois disso, imprimimos o status code dessa chamada. Se voltarmos a documentação, sabemos que isso está devidamente documentado lá. No caso, quando temos o exemplo de sucesso, ela afirma que retornará um código &lt;code&gt;200&lt;/code&gt; e quando tiver um erro, retornará algo com 4xx. &lt;/p&gt;

&lt;p&gt;Esse 4xx representa que retornará algum código da família 400. (400: bad request, 401: Unauthorized etc). Veja mais &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status" rel="noopener noreferrer"&gt;nesse artigo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwerp2mk94qrq3lfstilq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwerp2mk94qrq3lfstilq.png" alt="Exemplo de erro como está documentado" width="800" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nesse momento se executarmos o código exatamente como está, ele irá retornar um desses erros. No caso retornará um erro 400 com o seguinte JSON de erro&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"detail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Invalid token"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso está acontecendo justamente por não termos mudado o token no endereço ali em cima.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://apiadvisor.climatempo.com.br/api/v1/weather/locale/3477/current?token=your-app-token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mude o texto onde está &lt;code&gt;your-app-token&lt;/code&gt; para o token que aparecer no seu painel. CUIDADO para não deixar isso público e nem compartilhar isso com ninguém. &lt;/p&gt;

&lt;p&gt;Com isso passaremos a ter uma resposta com o padrão de sucesso como apresentado na documentação. Nesse caso, teremos um retorno &lt;code&gt;200&lt;/code&gt; e um JSON parecido com esse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3477&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"S&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s2"&gt;00e3o Paulo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"state"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"SP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"country"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"BR  "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"temperature"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"wind_direction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"SSE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"wind_velocity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"humidity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;94&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Chuva fraca"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"pressure"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1023&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"icon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"5n"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sensation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"2023-08-09 19:20:08"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Eu vou parar por aqui nesse exemplo para não ficar cansativo. Principalmente se pensarmos que esse primeiro post sobre esse tema foi bem direcionado para apresentar a API do ClimaTempo e a parte de código bem direcionada para um público iniciante, acredito que onde paramos é um bom momento. &lt;/p&gt;

&lt;p&gt;Nesse post conseguimos ver detalhes de como entender uma documentação de uma API. Vimos que o ClimaTempo pode ser um bom projeto pra praticarmos alguma tecnologia nova na hora de testar soluções de client http. &lt;/p&gt;

&lt;p&gt;E também oficializamos esse exemplo com um código básico usando o pacote &lt;code&gt;net/http&lt;/code&gt; do Go. &lt;/p&gt;

&lt;h3&gt;
  
  
  Próximos passos
&lt;/h3&gt;

&lt;p&gt;Provavelmente o próximo passo vai ser a evolução desse aqui. vamos melhorar um pouco nosso projeto transformando nosso JSON em uma struct por exemplo. &lt;/p&gt;

&lt;p&gt;Se você gostou desse post, curta e compartilhe nas redes. Qualquer duvida ou feedback deixe nos comentários e &lt;a href="https://linktr.ee/marcopollivier" rel="noopener noreferrer"&gt;me siga nas redes&lt;/a&gt; :) &lt;/p&gt;

&lt;p&gt;Até mais. &lt;/p&gt;

</description>
      <category>api</category>
      <category>beginners</category>
      <category>go</category>
      <category>rest</category>
    </item>
    <item>
      <title>Não se preocupe mais com o package manager do seu projeto NodeJS</title>
      <dc:creator>Marco Ollivier</dc:creator>
      <pubDate>Thu, 06 Jul 2023 23:25:07 +0000</pubDate>
      <link>https://forem.com/marcopollivier/nao-se-preocupe-mais-com-qual-package-manager-voce-esta-usando-em-seu-projeto-nodejs-34al</link>
      <guid>https://forem.com/marcopollivier/nao-se-preocupe-mais-com-qual-package-manager-voce-esta-usando-em-seu-projeto-nodejs-34al</guid>
      <description>&lt;p&gt;Eu que venho de outras tecnologias como Go, Clojure e Java, as vezes fico um pouco irritado com a quantidade de alternativas que são usadas de maneira tão ampla no universo NodeJS. Pra esse post específico eu ilustro com gerenciadores de pacote... meu deus... é npm, é yarn, é pnpm. &lt;br&gt;
Parece que cada dia aparece um novo. &lt;/p&gt;

&lt;p&gt;(tá... não é pra tanto, mas eu quero fazer um drama pra justificar o post)&lt;/p&gt;

&lt;p&gt;Mas fazendo aqui um mea-culpa, talvez isso seja um problema mais meu do que da tecnologia em si, já que até hoje minha memória muscular digita no terminal &lt;code&gt;lein lint:fix&lt;/code&gt; em vez de &lt;code&gt;yarn lint:fix&lt;/code&gt; ou qualquer outro comando que realmente funcione pra projetos Node. &lt;/p&gt;

&lt;p&gt;(pra quem não entendeu, lein é de Leiningen, o gerador de pacotes que eu usava pra trabalhar com Clojure) &lt;/p&gt;

&lt;p&gt;Mas meus problemas acabaram. Esses dias scrollando alguma rede social por aí, chegou ao meu conhecimento o &lt;code&gt;ni&lt;/code&gt;. Mas o que seria o Ni? Um novo gerador de pacotes? Não, mas ele vai acabar de vez com meus problemas em relação a projetos diferentes com gerenciadores diferentes. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1zv1c8t8qpomcfbv1itv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1zv1c8t8qpomcfbv1itv.png" alt=" " width="800" height="666"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  O Ni
&lt;/h1&gt;

&lt;p&gt;É tão simples usar o Ni, que escrever sobre ele também não demanda um texto muito grande. &lt;/p&gt;

&lt;p&gt;Basicamente é uma ferramenta desenvolvida pra você que tem vários projetos e, eventualmente, cada um com um package manager. O Ni simplesmente vai abstrair isso pra você e você pode passar a se preocupar apenas com um único padrão de comandos.&lt;/p&gt;

&lt;p&gt;O &lt;code&gt;Ni&lt;/code&gt; dá suporte a &lt;code&gt;npm&lt;/code&gt;, &lt;code&gt;yarn&lt;/code&gt;,&lt;code&gt;pnpm&lt;/code&gt;e &lt;code&gt;bun&lt;/code&gt; e com apenas um conjunto de comandos você trabalha com qualquer projeto que use um desses. &lt;/p&gt;

&lt;p&gt;Por exemplo: se eu quero adicionar um novo pacote no meu projeto Node, mas apenas no contexto de desenvolvimento, pra cada um dos geradores de pacotes acima, eu teria essas opções abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# npm i @types/node -D
# yarn add @types/node -D
# pnpm add -D @types/node
# bun add -d @types/node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Se você tem o Ni configurado na sua máquina, basta executar o comando &lt;code&gt;ni @types/node -D&lt;/code&gt; e ele vai identificar qual o gerenciador de pacotes você tá usando e encontrar qual desses comandos ele deveria executar por debaixo dos panos. &lt;/p&gt;

&lt;p&gt;Só por isso o Ni já se justifica pra mim, mas além disso, ele também é uma CLI bem interativa. O que pra mim é muito interessante quando estou tentando executar um projeto que eu ainda não conheço muito bem. &lt;/p&gt;

&lt;p&gt;Por exemplo: pra eu rodar algum comando que está configurado dentro do meu &lt;code&gt;package.json&lt;/code&gt; basta eu rodar &lt;code&gt;nr&lt;/code&gt; (ni run) e ele vai listar pra mim todos os comandos de scripts disponíveis nos &lt;code&gt;scripts&lt;/code&gt; do arquivo em um menu navegável pra ajudar na execução. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05psonvrjndhqwwbnu4i.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F05psonvrjndhqwwbnu4i.gif" alt=" " width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O Ni também tenta te ajudar na repetição de comandos. Se você executar o comando &lt;code&gt;nr -&lt;/code&gt; ele vai executar o último comando rodado. No caso, se eu rodei um &lt;code&gt;nr start:dev&lt;/code&gt;, na vez seguinte eu posso apenas executar o &lt;code&gt;nr -&lt;/code&gt; que ele vai executar o start:dev pra mim. &lt;/p&gt;

&lt;p&gt;E aqui se eu não te convenci, não sei mais como posso fazer isso, mas se curtiu, instalar também é absurdamente simples. Basta apenas executar o comando&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm i -g @antfu/ni
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;E se quiser olhar como o projeto foi construído e até mesmo colaborar com o projeto, o Github é esse aqui. &lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/antfu-collective" rel="noopener noreferrer"&gt;
        antfu-collective
      &lt;/a&gt; / &lt;a href="https://github.com/antfu-collective/ni" rel="noopener noreferrer"&gt;
        ni
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      💡 Use the right package manager
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;ni&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;del&gt;&lt;em&gt;&lt;code&gt;npm i&lt;/code&gt; in a yarn project, again? F**k!&lt;/em&gt;&lt;/del&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ni&lt;/strong&gt; - use the right package manager&lt;/p&gt;



&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;npm i -g @antfu/ni
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="https://docs.npmjs.com/cli/v6/commands/npm" rel="nofollow noopener noreferrer"&gt;npm&lt;/a&gt; · &lt;a href="https://yarnpkg.com" rel="nofollow noopener noreferrer"&gt;yarn&lt;/a&gt; · &lt;a href="https://pnpm.io/" rel="nofollow noopener noreferrer"&gt;pnpm&lt;/a&gt; · &lt;a href="https://bun.sh/" rel="nofollow noopener noreferrer"&gt;bun&lt;/a&gt; · &lt;a href="https://deno.land/" rel="nofollow noopener noreferrer"&gt;deno&lt;/a&gt;&lt;/p&gt;
&lt;br&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;
&lt;code&gt;ni&lt;/code&gt; - install&lt;/h3&gt;
&lt;/div&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;ni

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; npm install&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; yarn install&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; pnpm install&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; bun install&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; deno install&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;ni vite

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; npm i vite&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; yarn add vite&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; pnpm add vite&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; bun add vite&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; deno add vite&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;ni @types/node -D

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; npm i @types/node -D&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; yarn add @types/node -D&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; pnpm add -D @types/node&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; bun add -d @types/node&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; deno add -D @types/node&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;ni -P

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; npm i --omit=dev&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; yarn install --production&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; pnpm i --production&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; bun install --production&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; (deno not supported)&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;ni --frozen

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; npm ci&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; yarn install --frozen-lockfile (Yarn 1)&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; yarn install --immutable (Yarn Berry)&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; pnpm install --frozen-lockfile&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; bun install --frozen-lockfile&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; deno install --frozen&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;ni&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/antfu-collective/ni" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusão
&lt;/h1&gt;

&lt;p&gt;Pra pessoas como eu que trabalho em várias frentes - trabalho, voluntariado, comunidade etc - ter uma ferramenta que me ajuda em coisas pequenas que não deveriam tomar mais do que alguns poucos segundos faz muita diferença e por isso eu curti tanto a proposta do Ni. Espero que, de alguma forma, esse post também ajude você a ganhar um pouquinho mais de produtividade. &lt;/p&gt;

</description>
      <category>node</category>
      <category>yarn</category>
      <category>npm</category>
      <category>pnpm</category>
    </item>
    <item>
      <title>XML Parsing em NodeJS com XMLBuilder2</title>
      <dc:creator>Marco Ollivier</dc:creator>
      <pubDate>Sun, 16 Apr 2023 20:13:37 +0000</pubDate>
      <link>https://forem.com/marcopollivier/xml-parsing-em-nodejs-com-xmlbuilder2-1p0e</link>
      <guid>https://forem.com/marcopollivier/xml-parsing-em-nodejs-com-xmlbuilder2-1p0e</guid>
      <description>&lt;p&gt;Bom, como dito no post que serviu como preâmbulo, eu tive um primeiro momento onde eu pensei que não iria ter acesso a definição do WebService. Dessa forma minha vida ficaria um pouco mais complexa. Não seria exatamente o fim do mundo, mas eu teria que fazer parsing de XML e isso é algo relativamente chato. &lt;/p&gt;

&lt;p&gt;Bom. Foi quando eu conhecia a biblioteca XMLBuilder. Mais precisamente a v2 dessa lib (elas estão em repos diferentes). &lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/oozcitak" rel="noopener noreferrer"&gt;
        oozcitak
      &lt;/a&gt; / &lt;a href="https://github.com/oozcitak/xmlbuilder2" rel="noopener noreferrer"&gt;
        xmlbuilder2
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      An XML builder for node.js
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;xmlbuilder2&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;An XML builder for &lt;a href="https://nodejs.org/" rel="nofollow noopener noreferrer"&gt;node.js&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://opensource.org/licenses/MIT" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/cb13e8ae166f8936f7aaab0c2b9b0557324b1950491392ac75c9f2efc3333308/68747470733a2f2f62616467656e2e6e65742f6769746875622f6c6963656e73652f6f6f7a636974616b2f786d6c6275696c64657232" alt="License"&gt;&lt;/a&gt;
&lt;a href="https://www.npmjs.com/package/xmlbuilder2" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a902c245cbc21ebc5816fe9ac21a814ba15a897ba5ec7c4f9482ece2436d67f6/68747470733a2f2f62616467656e2e6e65742f6e706d2f762f786d6c6275696c64657232" alt="NPM Version"&gt;&lt;/a&gt;
&lt;a href="https://www.npmjs.com/package/xmlbuilder2" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/730b855c7b67df4c4fd39ef06b55b06c489a65ea47f88862ef9d23e01654806d/68747470733a2f2f62616467656e2e6e65742f6e706d2f646d2f786d6c6275696c64657232" alt="NPM Downloads"&gt;&lt;/a&gt;
&lt;a href="https://www.jsdelivr.com/package/npm/xmlbuilder2" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/2e23a7fdb0936049b1664947b71beb670eae24ecc133df83f8fed06dbf6c0bb0/68747470733a2f2f62616467656e2e6e65742f6a7364656c6976722f686974732f6e706d2f786d6c6275696c64657232" alt="jsDelivr"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/oozcitak/xmlbuilder2/actions" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/oozcitak/xmlbuilder2/workflows/build/badge.svg" alt="Node.js CI"&gt;&lt;/a&gt;
&lt;a href="https://codecov.io/gh/oozcitak/xmlbuilder2" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a45993f37df4bd3699e44bdb15e3196f3e64eca26e6fee480906573f8fc9b2d1/68747470733a2f2f636f6465636f762e696f2f67682f6f6f7a636974616b2f786d6c6275696c646572322f6272616e63682f6d61737465722f67726170682f62616467652e737667" alt="Code Coverage"&gt;&lt;/a&gt;
&lt;a href="https://david-dm.org/oozcitak/xmlbuilder2" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0d779678048f7614589fac62401bf063ac91c1742d69f337ac31494dfafa00c5/68747470733a2f2f62616467656e2e6e65742f64617669642f6465702f6f6f7a636974616b2f786d6c6275696c64657232" alt="Dev Dependency Status"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Installation:&lt;/h3&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install xmlbuilder2&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Documentation:&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;See: &lt;a href="https://oozcitak.github.io/xmlbuilder2/" rel="nofollow noopener noreferrer"&gt;https://oozcitak.github.io/xmlbuilder2/&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Usage:&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;xmlbuilder2&lt;/code&gt; is a wrapper around DOM nodes which adds chainable functions to make it easier to create and work with XML documents. For example the following XML document:&lt;/p&gt;
&lt;div class="highlight highlight-text-xml notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&amp;lt;?&lt;span class="pl-ent"&gt;xml&lt;/span&gt;&lt;span class="pl-e"&gt; version&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;1.0&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;?&amp;gt;
&amp;lt;&lt;span class="pl-ent"&gt;root&lt;/span&gt; &lt;span class="pl-e"&gt;att&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;val&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;
  &amp;lt;&lt;span class="pl-ent"&gt;foo&lt;/span&gt;&amp;gt;
    &amp;lt;&lt;span class="pl-ent"&gt;bar&lt;/span&gt;&amp;gt;foobar&amp;lt;/&lt;span class="pl-ent"&gt;bar&lt;/span&gt;&amp;gt;
  &amp;lt;/&lt;span class="pl-ent"&gt;foo&lt;/span&gt;&amp;gt;
  &amp;lt;&lt;span class="pl-ent"&gt;baz&lt;/span&gt;/&amp;gt;
&amp;lt;/&lt;span class="pl-ent"&gt;root&lt;/span&gt;&amp;gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;can be created with the following function chain:&lt;/p&gt;
&lt;div class="highlight highlight-source-js notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; create &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;require&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'xmlbuilder2'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;root&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;create&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-c1"&gt;version&lt;/span&gt;: &lt;span class="pl-s"&gt;'1.0'&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
  &lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;ele&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'root'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-c1"&gt;att&lt;/span&gt;: &lt;span class="pl-s"&gt;'val'&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
    &lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;ele&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'foo'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
      &lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;ele&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'bar'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;txt&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'foobar'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;up&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
    &lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;up&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
    &lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;ele&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'baz'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;up&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;
  &lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;up&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/oozcitak/xmlbuilder2" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Custo x Benefício da biblioteca
&lt;/h2&gt;

&lt;p&gt;Eu não estou há taaantos anos assim no universo JS/TS. Meu maior background é de Java, Go e Clojure. Dessa forma eu sempre fico com um pé atrás de sair usando qualquer biblioteca que eu encontro por aí. Então eu recorri ao &lt;a href="https://snyk.io/advisor/npm-package/xmlbuilder2" rel="noopener noreferrer"&gt;snyk.io&lt;/a&gt; para "qualidade" da biblioteca. &lt;/p&gt;

&lt;p&gt;Eu coloquei qualidade entre aspas, porque isso não é o que realmente vai definir a qualidade dela, mas pelo menos me dá um score de algumas coisas que eu acho importante como: vulnerabilidades de segurança encontradas, quantidade de novos downloads por semana e suporte frequente pelo criados.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw4kqb2hbl4t2yp1m0dxd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw4kqb2hbl4t2yp1m0dxd.png" alt="Package Health Score 16abr2023" width="387" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bom... a nota foi de 79 de 100. Não é das melhores, mas passa de ano. Uma das coisas que impactou a nota foi o tempo do último release. Mas eu levei em conta uma coisa pra decidir acabar utilizando: XML não é exatamente uma tecnologia que tem sofrido grandes mudanças nos últimos tempos. E se a lib não apresenta problemas com segurança, talvez faça sentido não ter sofrido alterações recentemente. &lt;/p&gt;

&lt;h2&gt;
  
  
  Utilização
&lt;/h2&gt;

&lt;p&gt;Bom. Chega de enrolação. Pra demonstra como foi a utilização da biblioteca eu criei um projeto NodeJS bem simples que você vai encontrar nesse repo aqui...&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/marcopollivier" rel="noopener noreferrer"&gt;
        marcopollivier
      &lt;/a&gt; / &lt;a href="https://github.com/marcopollivier/practice.node-with-xml" rel="noopener noreferrer"&gt;
        practice.node-with-xml
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Projeto de PoC sobre como manipular XMLs com NodeJS de uma forma menos custosa 
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;practice.node-with-xml&lt;/h1&gt;

&lt;/div&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/marcopollivier/practice.node-with-xml" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Pra instalar é o básico&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm install xmlbuilder2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E como base vamos começar com um XML básico. Como, no caso de não termos um WSDL, o que faremos é uma requisição HTTP usando o método POST e passando um XML no payload, aqui vamos nos ater a simplesmente como vamos criar nosso XML pra enviar nesse payload. Todo o resto iria apenas atrapalhar nosso objetivo. &lt;/p&gt;

&lt;p&gt;Então vamos tomar como base o seguinte XML inicialmente (que eu vou tentar deixar o mais próximo possível do XML de uma WebService SOAP):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;soap:Envelope&lt;/span&gt; &lt;span class="na"&gt;xmlns:soap=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.xmlsoap.org/soap/envelope/"&lt;/span&gt;
               &lt;span class="na"&gt;xmlns:soapenc=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.xmlsoap.org/soap/encoding/"&lt;/span&gt;
               &lt;span class="na"&gt;xmlns:tns=&lt;/span&gt;&lt;span class="s"&gt;"http://wms2.marcopollivier.dev/soap/webservice.xpto"&lt;/span&gt;
               &lt;span class="na"&gt;xmlns:types=&lt;/span&gt;&lt;span class="s"&gt;"http://wms2.marcopollivier.dev/soap/webservice.xpto/encodedTypes"&lt;/span&gt;
               &lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/XMLSchema-instance"&lt;/span&gt;
               &lt;span class="na"&gt;xmlns:xsd=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/XMLSchema"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;soap:Body&lt;/span&gt; &lt;span class="na"&gt;soap:encodingStyle=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.xmlsoap.org/soap/encoding/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="c"&gt;&amp;lt;!-- Cadastra Livros - Requisição --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;tns:CadastraLivros&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"id1"&lt;/span&gt; &lt;span class="na"&gt;xsi:type=&lt;/span&gt;&lt;span class="s"&gt;"tns:CadastraLivros"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;LivrosArray&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#id2"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/tns:CadastraLivros&amp;gt;&lt;/span&gt;

        &lt;span class="c"&gt;&amp;lt;!-- Livros - Array --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;soapenc:Array&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"id2"&lt;/span&gt; &lt;span class="na"&gt;soapenc:arrayType=&lt;/span&gt;&lt;span class="s"&gt;"tns:Livro[1]"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Item&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#id3"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/soapenc:Array&amp;gt;&lt;/span&gt;

        &lt;span class="c"&gt;&amp;lt;!-- Livros - Array --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;tns:Livro&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"id3"&lt;/span&gt; &lt;span class="na"&gt;xsi:type=&lt;/span&gt;&lt;span class="s"&gt;"tns:Livro"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Pedido&lt;/span&gt; &lt;span class="na"&gt;xsi:type=&lt;/span&gt;&lt;span class="s"&gt;"xsd:string"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;O Conde de Monte Cristo&lt;span class="nt"&gt;&amp;lt;/Pedido&amp;gt;&lt;/span&gt;

            &lt;span class="nt"&gt;&amp;lt;ExemplaresArray&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#id4"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/tns:Livro&amp;gt;&lt;/span&gt;

        &lt;span class="c"&gt;&amp;lt;!-- Exemplares - Array --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;soapenc:Array&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"id4"&lt;/span&gt; &lt;span class="na"&gt;soapenc:arrayType=&lt;/span&gt;&lt;span class="s"&gt;"tns:Exemplar[1]"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Item&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#id5"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/soapenc:Array&amp;gt;&lt;/span&gt;

        &lt;span class="c"&gt;&amp;lt;!-- Exemplar --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;tns:Exemplar&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"id5"&lt;/span&gt; &lt;span class="na"&gt;xsi:type=&lt;/span&gt;&lt;span class="s"&gt;"tns:Exemplar"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Quantidade&lt;/span&gt; &lt;span class="na"&gt;xsi:type=&lt;/span&gt;&lt;span class="s"&gt;"xsd:nonNegativeInteger"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;5&lt;span class="nt"&gt;&amp;lt;/Quantidade&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;AnoEdicao&lt;/span&gt; &lt;span class="na"&gt;xsi:type=&lt;/span&gt;&lt;span class="s"&gt;"xsd:string"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;2022&lt;span class="nt"&gt;&amp;lt;/Pedido&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/tns:Exemplar&amp;gt;&lt;/span&gt;


    &lt;span class="nt"&gt;&amp;lt;/soap:Body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/soap:Envelope&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eu sei que o XML ficou meio grande, mas eu queria representar algumas peculiaridades que são importantes desse xml que eu considerei importantes estarem aqui&lt;/p&gt;

&lt;h3&gt;
  
  
  Primeira tentativa: A solução padrão
&lt;/h3&gt;

&lt;p&gt;Bom. O primeiro exemplo que a biblioteca oferece é você fazer de uma forma em que você meio que navega na hierarquia  do XML. &lt;/p&gt;

&lt;p&gt;Como essa biblioteca por baixo dos panos utiliza a estratégia de XPath pra navegar nas tags, essa estratégia é até meio óbvia e, talvez, por isso seja a primeira apresentada. &lt;/p&gt;

&lt;p&gt;E francamente, eu vou fazer só as primeiras tags, porque essa também é a forma mais verbosa...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;soap:Envelope&lt;/span&gt; &lt;span class="na"&gt;xmlns:soap=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.xmlsoap.org/soap/envelope/"&lt;/span&gt;
               &lt;span class="na"&gt;xmlns:soapenc=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.xmlsoap.org/soap/encoding/"&lt;/span&gt;
               &lt;span class="na"&gt;xmlns:tns=&lt;/span&gt;&lt;span class="s"&gt;"http://wms2.marcopollivier.dev/soap/webservice.xpto"&lt;/span&gt;
               &lt;span class="na"&gt;xmlns:types=&lt;/span&gt;&lt;span class="s"&gt;"http://wms2.marcopollivier.dev/soap/webservice.xpto/encodedTypes"&lt;/span&gt;
               &lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/XMLSchema-instance"&lt;/span&gt;
               &lt;span class="na"&gt;xmlns:xsd=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/XMLSchema"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Talvez a parte mais chata seja esse começo. Onde eu tenho que definir alguns muitos atributos no elemento do &lt;code&gt;soap:Envelop&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ele&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;soap:Envelope&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xmlns:soap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://schemas.xmlsoap.org/soap/envelope/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xmlns:soapenc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://schemas.xmlsoap.org/soap/encoding/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xmlns:tns&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://wms2.marcopollivier.dev/soap/webservice.xpto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

                          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xmlns:types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://wms2.marcopollivier.dev/soap/webservice.xpto/encodedTypes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xmlns:xsi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://www.w3.org/2001/XMLSchema-instance&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xmlns:xsd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://www.w3.org/2001/XMLSchema&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;up&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Só essa primeira parte que representa o &lt;code&gt;soap:envelop&lt;/code&gt; já parece que vai ser uma forma muito verbosa. E isso se confirma com a continuação do código. &lt;/p&gt;

&lt;p&gt;Se você bem notou, no final tem uma chamada de função &lt;code&gt;up()&lt;/code&gt;. Lembra que eu disse que essa lib usa a estratégia de XPath por baixo dos panos? Aqui isso fica bem claro. Já que no, se eu não quero continuar aninhando elementos, eu tenho que dizer que eu quero subir um nível antes de criar o próximo. Ou seja:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;el('a').el('b').el('c')&lt;/code&gt; vai gerar algo como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;b&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;c&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/c&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;/b&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;de modo que se você mudar para &lt;code&gt;el('a').el('b').up().el('c').up()&lt;/code&gt;, você terá algo como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;b&amp;gt;&amp;lt;/b&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;c&amp;gt;&amp;lt;/c&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Então, dessa forma, pra representar o próximo nível do nosso exemplo (&lt;code&gt;soap:body&lt;/code&gt;) basta fazer algo do tipo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ele&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;soap:Envelope&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xmlns:soap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://schemas.xmlsoap.org/soap/envelope/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xmlns:soapenc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://schemas.xmlsoap.org/soap/encoding/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xmlns:tns&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://wms2.marcopollivier.dev/soap/webservice.xpto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

                          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xmlns:types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://wms2.marcopollivier.dev/soap/webservice.xpto/encodedTypes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xmlns:xsi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://www.w3.org/2001/XMLSchema-instance&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;xmlns:xsd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://www.w3.org/2001/XMLSchema&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ele&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;soap:Body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;soapenc:arrayType&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tns:Livro[1]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;up&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E agora o resto é repetição... &lt;/p&gt;

&lt;h3&gt;
  
  
  Segunda tentativa: Usar um objeto JSON
&lt;/h3&gt;

&lt;p&gt;Sim. A lib oferece essa opção. E eu não apresentei ela primeiro porque eu queria reforçar que existe uma outra forma que pode ter suas vantagens. &lt;/p&gt;

&lt;p&gt;O modelo anterior pode se mostrar verboso e repetitivo pra XMLs muito grandes (o que é o nosso caso), mas querendo ou não, você vai ter mais controle do que você tá fazendo. Pra XMLs mais simples, eu acho que iria pra essa opção. &lt;/p&gt;

&lt;p&gt;Entretanto não dá pra negar o apelo que tem a possibilidade de criar um XML por meio de um JSON. &lt;/p&gt;

&lt;p&gt;Só que logo uma coisa vem na minha cabeça: o XML tem os atributos, que, como vimos, é bem comum em XMLs SOAP. &lt;/p&gt;

&lt;p&gt;Mas sim... ficou muito mais simples. Tanto que eu me empolguei e fiz mais que no exemplo anterior.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;soap:Envelope&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@xmlns:soap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://schemas.xmlsoap.org/soap/envelope/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@xmlns:soapenc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://schemas.xmlsoap.org/soap/encoding/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@xmlns:tns&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://wms2.marcopollivier.dev/soap/webservice.xpto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@xmlns:types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://wms2.marcopollivier.dev/soap/webservice.xpto/encodedTypes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@xmlns:xsi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://www.w3.org/2001/XMLSchema-instance&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@xmlns:xsd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://www.w3.org/2001/XMLSchema&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;soap:Body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@soap:encodingStyle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://schemas.xmlsoap.org/soap/encoding/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tns:CadastraLivros&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@xsi:type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tns:CadastraLivros&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;LivrosArray&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@href&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#id2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como você já deve ter reparado, esse modelo usa o @ na frente pra poder indicar que aquilo é um atributo e que ele precisa saber montar de acordo. &lt;/p&gt;

&lt;p&gt;Bom. Tudo vai indo bem, até que esbarramos no seguinte problema: Como o XML tem atributos que conseguem distinguir elementos com o mesmo nome, o nosso XML pode ter elementos repetidos no mesmo nível. O que é o caso dos elementos&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;
        &lt;span class="nt"&gt;&amp;lt;soapenc:Array&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"id2"&lt;/span&gt; &lt;span class="na"&gt;soapenc:arrayType=&lt;/span&gt;&lt;span class="s"&gt;"tns:Livro[1]"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Item&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#id3"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/soapenc:Array&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;soapenc:Array&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"id4"&lt;/span&gt; &lt;span class="na"&gt;soapenc:arrayType=&lt;/span&gt;&lt;span class="s"&gt;"tns:Exemplar[1]"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Item&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#id5"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/soapenc:Array&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Entretanto, quando representamos isso no JSON ele simplesmente sobrescreve o primeiro elemento pelo segundo. &lt;/p&gt;

&lt;p&gt;Para tentar resolver isso, eu tentei &lt;em&gt;appendar&lt;/em&gt; o elemento, mas também não deu muito certo &lt;code&gt;original.root().ele('soap:Body').ele('aaa')&lt;/code&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Talvez ter chegado no final desse artigo tenha sido um pouco frustrante, mas foi importante pra mostrar que faz muita diferença a forma que integramos entre serviços. E que, quando você opta por fazer um WebService SOAP você vai criar um nível de complicação que talvez não seja necessário. Principalmente pensando que você tem outras formas de integração usando o mesmo protocolo e que vai gerar bem menos trabalho. &lt;/p&gt;

&lt;p&gt;Quanto a biblioteca, ela se mostrou interessante, mas esbarramos em problemas que precisamos dar uma volta grande pra tentar resolver e, dependendo do problema, vamos esbarrar em algumas limitações. Como foi o caso da sobrescrita do elemento. &lt;/p&gt;

&lt;p&gt;Francamente eu nem achei que valia mais a pena tentar resolver esse problema, pois nesse meio tempo descobri que eu iria ter acesso ao WSDL desse WS. Então desse texto, fica o quanto essa lib pode te ajudar e também algumas limitações dependendo do caso. Se você quiser avançar daqui e postar nos comentários como deixar essa solução redondinha, eu agradeço e certamente te darei os devidos créditos quando eu ajustar o texto. :) &lt;/p&gt;

&lt;p&gt;Se você não tiver opções e tiver que integrar com um WebService SOAP, buque saber se o WSDL está disponível de alguma forma. Dessa forma sua vida ficará mais simples (como veremos no próximo texto). &lt;/p&gt;

&lt;p&gt;Vale aqui eu finalizar com uma experiência passada com esse mesmo tipo de problema: nessa minha experiência prévia, nós havíamos feito uma integração também em SOAP parseando XML. O que tivemos foi uma alteração de contrato do lado do fornecedor do WS. Nós não conseguimos identificar que havia sido feita uma mudança e a falha na integração gerou uma perda financeira considerável. Então aqui ficam duas lições. Cuidado com os contratos das integrações e estejam com a observabilidade dos seus serviços em dia. &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>node</category>
      <category>soap</category>
    </item>
    <item>
      <title>SOAP com TypeScript em pleno 2023</title>
      <dc:creator>Marco Ollivier</dc:creator>
      <pubDate>Sun, 16 Apr 2023 20:12:35 +0000</pubDate>
      <link>https://forem.com/marcopollivier/soap-com-typescript-em-pleno-2023-5ako</link>
      <guid>https://forem.com/marcopollivier/soap-com-typescript-em-pleno-2023-5ako</guid>
      <description>&lt;h2&gt;
  
  
  Soap soup
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;TL;DR&lt;/em&gt;&lt;/strong&gt;: blablabla tive que fazer um parsing XML e depois descobri que ia conseguir usar o WSDL. Se não quiser ler o textão, vai pro próximo tópico sobre como eu resolvi primeiro o parsing XML. &lt;/p&gt;

&lt;p&gt;O ano é 2023. Estamos falando em gRPC, tRPC, Rest, GraphQL blablabla. Pois eis que do nada surge uma integração que precisa ser feita via SOAP e XML. Sim... você não entendeu errado... um Web Service... SOAP... com direito a XML.. e tudo mais. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ilf6iszushyhzb36364.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ilf6iszushyhzb36364.png" alt="Em pleno 2023..." width="720" height="1097"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pois é. Fui transportado no tempo e automaticamente me lembrei de quando eu estava na faculdade, nos idos de 2009. Quando em uma cadeira de Java nós falávamos de JAX-WS e de como poderíamos gerar classes stubs pelo Eclipse. Meu Deus... aqui a nostalgia não vem acompanhada de saudade. Também impossível não lembrar dos trocadilhos com sabão, sopa ou coisas que tem sonoridade parecida. Inclusive a capa desse artigo é uma Sopa de Sabão que eu pedi pro Midjourney gerar pra mim haha. &lt;/p&gt;

&lt;p&gt;Mas bem. Estamos em 2023 e hoje eu estou construindo soluções em JavaScript... ou melhor: em TypeScript. E tenho como fiel companheiro o &lt;a href="https://www.fastify.io/" rel="noopener noreferrer"&gt;Fastify&lt;/a&gt; para que as coisas fiquem menos dolorosas. &lt;/p&gt;

&lt;p&gt;Mas quem foi que disse que a vida é simples? Pois é. Eu contava que eu teria o WSDL pra facilitar minha vida e, em um primeiro momento eu tive uma negativa em relação a isso. &lt;/p&gt;

&lt;p&gt;Dessa forma eu teria que fazer o parsing do XML... na mão. Dando um spoiler, depois eu consegui o WSDL e a vida vai ficar mais fácil, mas eu já tinha feito uma PoC de como eu faria o parsing desse XML na mão então vai ser a primeira parte dessa sequência de posts. Espero que você não tenha que precisar usa-los, mas se precisar, espero que sejam úteis hehe. &lt;/p&gt;

&lt;h2&gt;
  
  
  Alinhando os patos
&lt;/h2&gt;

&lt;p&gt;Antes de irmos pro primeiro texto vamos alinhar alguns conceitos para quem não souber do que eu estou falando consiga ficar na mesma página. &lt;/p&gt;

&lt;h3&gt;
  
  
  WebService, SOAP, SOA e até mesmo REST
&lt;/h3&gt;

&lt;p&gt;Talvez o termo menos problemático aqui seja &lt;code&gt;WebService&lt;/code&gt;. Vamos defini-lo como &lt;code&gt;"uma aplicação distribuída cujos componentes podem ser aplicados e executados em dispositivos distintos." -- Martin Kalim&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Provavelmente você pensou em &lt;code&gt;APIs Rest&lt;/code&gt;. E não está de todo errado. Inclusive há anos atrás, bibliografias dividiam WebServices em dois grupos: baseados em SOAP e de "estilo" REST. Inclusive considerando SOAP uma espécie de caso especial do REST. Muito disso tem relação com o fato de ambos rodarem em cima do protocolo HTTP. &lt;/p&gt;

&lt;p&gt;Outro ponto que ajuda a confundir as definições é quando entra a definição de SOA no meio. Originalmente &lt;code&gt;SOAP&lt;/code&gt; significa &lt;code&gt;Simple Object Access Protocol&lt;/code&gt; enquanto &lt;code&gt;SOA&lt;/code&gt; significa &lt;code&gt;Service Oriented Architecture&lt;/code&gt;. Então como podemos ver pelos próprios nomes, SOA é um estilo arquitetural enquanto SOAP é um dialeto XML. &lt;/p&gt;

&lt;p&gt;Aqui vale frisar que nosso foco não é SOA, então paramos por aqui em relação a esse termo e que, SOAP e SOA são conceitos que podem ser utilizados de forma totalmente independente entre si. &lt;/p&gt;

&lt;p&gt;Se você quiser uma visualização simples de como funciona um WebService SOAP, abra seu postman e chame o seguinte serviço (exatamente da mesma forma que você faria com um endpoint Restful).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;POST&lt;/span&gt; &lt;span class="nn"&gt;/webservicesserver/NumberConversion.wso&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;www.dataaccess.com&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;text/xml&lt;/span&gt;
&lt;span class="na"&gt;Content-Length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;276&lt;/span&gt;

&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;soap:Envelope&lt;/span&gt; &lt;span class="na"&gt;xmlns:soap=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.xmlsoap.org/soap/envelope/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;soap:Body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;NumberToWords&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://www.dataaccess.com/webservicesserver/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;ubiNum&amp;gt;&lt;/span&gt;500&lt;span class="nt"&gt;&amp;lt;/ubiNum&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/NumberToWords&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/soap:Body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/soap:Envelope&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse WebService traduz um número inteiro para sua representação por extenso. E o retorno dele será.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;soap:Envelope&lt;/span&gt; &lt;span class="na"&gt;xmlns:soap=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.xmlsoap.org/soap/envelope/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;soap:Body&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;m:NumberToWordsResponse&lt;/span&gt; &lt;span class="na"&gt;xmlns:m=&lt;/span&gt;&lt;span class="s"&gt;"http://www.dataaccess.com/webservicesserver/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;m:NumberToWordsResult&amp;gt;&lt;/span&gt;five hundred &lt;span class="nt"&gt;&amp;lt;/m:NumberToWordsResult&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/m:NumberToWordsResponse&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/soap:Body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/soap:Envelope&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;  &amp;lt;soap:Body&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;    &amp;lt;NumberToWords xmlns="http://www.dataaccess.com/webservicesserver/"&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;      &amp;lt;ubiNum&amp;gt;500&amp;lt;/ubiNum&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;    &amp;lt;/NumberToWords&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;  &amp;lt;/soap:Body&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;/soap:Envelope&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;maxBodyLength&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;Infinity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://www.dataaccess.com/webservicesserver/NumberConversion.wso&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/xml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perceba que ele é um XML bem diferentão, mas ainda é um XML. E como sua requisição usa como base o protocolo HTTP, fica muito fácil fazer uma requisição dessa forma. &lt;/p&gt;

&lt;p&gt;O problema é que os serviços dificilmente são simples dessa forma. E se precisarmos integrar com um WebService que tenha uma quantidade grande de métodos ou a informação tenha uma estrutura mais complexa, fazer a requisição dessa forma será bem mais complicado. E veremos isso nos próximos dois artigos dessa série. &lt;/p&gt;

&lt;h3&gt;
  
  
  O WSDL
&lt;/h3&gt;

&lt;p&gt;Eu comentei que dependendo do que tivermos no nosso WebService, essa integração pode ser bem complexa. Existe uma forma de tentar fazer com que isso seja menos problemático? &lt;/p&gt;

&lt;p&gt;A resposta é sim. Não é bonito, mas torna a vida mais simples. &lt;/p&gt;

&lt;p&gt;Lá pra 2010 quando eu estava ainda na faculdade, eu tive uma cadeira sobre isso e por mais que eu lembre de poucas coisas da época, uma coisa ficou na minha cabeça: os stubs que eram gerados via Eclipse por meio de um arquivo chamado WSDL. &lt;/p&gt;

&lt;p&gt;O &lt;code&gt;WSDL&lt;/code&gt; significa &lt;code&gt;WebService Description Language&lt;/code&gt; e também é baseado em XML. Ele vai servir justamente pra definir a interface dos serviços SOAP e nele estarão coisas como o formato de entrada e de saída, os tipos que precisam ser passados, quais métodos estão disponíveis etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;wsdl:definitions&lt;/span&gt; 
 &lt;span class="na"&gt;xmlns:soap=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.xmlsoap.org/wsdl/soap/"&lt;/span&gt; 
 &lt;span class="na"&gt;xmlns:tm=&lt;/span&gt;&lt;span class="s"&gt;"http://microsoft.com/wsdl/mime/textMatching/"&lt;/span&gt; 
 &lt;span class="na"&gt;xmlns:soapenc=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.xmlsoap.org/soap/encoding/"&lt;/span&gt; 
 &lt;span class="na"&gt;xmlns:mime=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.xmlsoap.org/wsdl/mime/"&lt;/span&gt; 
 &lt;span class="na"&gt;xmlns:tns=&lt;/span&gt;&lt;span class="s"&gt;"http://tempuri.org/"&lt;/span&gt; 
 &lt;span class="na"&gt;xmlns:s=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/XMLSchema"&lt;/span&gt; 
 &lt;span class="na"&gt;xmlns:soap12=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.xmlsoap.org/wsdl/soap12/"&lt;/span&gt; 
 &lt;span class="na"&gt;xmlns:http=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.xmlsoap.org/wsdl/http/"&lt;/span&gt; 
 &lt;span class="na"&gt;xmlns:wsdl=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.xmlsoap.org/wsdl/"&lt;/span&gt; 
 &lt;span class="na"&gt;targetNamespace=&lt;/span&gt;&lt;span class="s"&gt;"http://tempuri.org/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;wsdl:types&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;s:schema&lt;/span&gt; &lt;span class="na"&gt;elementFormDefault=&lt;/span&gt;&lt;span class="s"&gt;"qualified"&lt;/span&gt; &lt;span class="na"&gt;targetNamespace=&lt;/span&gt;&lt;span class="s"&gt;"http://tempuri.org/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;s:element&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Add"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;s:complexType&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;s:sequence&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;s:element&lt;/span&gt; &lt;span class="na"&gt;minOccurs=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;maxOccurs=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"intA"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"s:int"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;s:element&lt;/span&gt; &lt;span class="na"&gt;minOccurs=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;maxOccurs=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"intB"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"s:int"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/s:sequence&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/s:complexType&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/s:element&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;s:element&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"AddResponse"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;s:complexType&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;s:sequence&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;s:element&lt;/span&gt; &lt;span class="na"&gt;minOccurs=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;maxOccurs=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"AddResult"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"s:int"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/s:sequence&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/s:complexType&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/s:element&amp;gt;&lt;/span&gt;

...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repare que também é um XML, mas é diferente. Nele você encontra o nome dos parametros, os tipos aceitos e o nome dos métodos. Assim como o padrão de suas respostas. &lt;/p&gt;

&lt;p&gt;Com essa documento a vida fica consideravelmente mais simples, pois muitas tecnologias oferecem ferramentas para que você crie o código que será usado pra integrar com o WebService por meio desse documento. &lt;/p&gt;

&lt;p&gt;Em Java por exemplo, existe o &lt;code&gt;wsimport&lt;/code&gt; que vai escrever quase que completamente um cliente que será usado para consumir o serviço disponibilizado. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Esse texto é inicial pra dar o termômetro do que precisaremos fazer e também serve como alinhamento de entendimento de alguns termos que por muito se confundem entre si. &lt;/p&gt;

&lt;p&gt;Pros próximos passos, vamos ver as duas maneiras de fazer uma integração com um WebService SOAP. Primeiro vamos fazer um parsing direto do XML e depois vamos usar libs que entendem o padrão WSDL para que nossas vidas sejam mais fáceis. &lt;/p&gt;

&lt;p&gt;Até lá :) &lt;/p&gt;

</description>
      <category>soap</category>
      <category>typescript</category>
      <category>fastify</category>
      <category>nestjs</category>
    </item>
    <item>
      <title>READMEs: o primeiro passo para uma boa documentação</title>
      <dc:creator>Marco Ollivier</dc:creator>
      <pubDate>Wed, 12 Oct 2022 19:36:01 +0000</pubDate>
      <link>https://forem.com/marcopollivier/readmes-o-primeiro-passo-para-uma-boa-documentacao-2aj9</link>
      <guid>https://forem.com/marcopollivier/readmes-o-primeiro-passo-para-uma-boa-documentacao-2aj9</guid>
      <description>&lt;h2&gt;
  
  
  Do começo
&lt;/h2&gt;

&lt;p&gt;Aqui vai um pouco de contexto como como eu cheguei as conclusões que vou falar daqui a pouco. Se quiser pular essa parte, vá direto para o &lt;strong&gt;Better read-me's&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Acho que uma das coisas que não posso negar sobre ter passado 2 anos e meio trabalhando no Nubank é que lá foi uma grande escola de boas práticas. Tanto para aprender uma técnica nova quanto pra consolidar práticas que eu já adotava de alguma forma lá era um ambiente que sempre me trazia a oportunidade de aperfeiçoar alguma técnica. Uma dessas técnicas é sobre documentar documentar e documentar. Escrever e manter documentações talvez tenha sido uma das coisas que eu mais aprendi/aperfeiçoei nesses anos. &lt;/p&gt;

&lt;p&gt;Como bom dev, eu sempre me preocupei mais me documentar fluxos e, de alguma forma, tinha um pouco em mim o ceticismo de que manter documentação era algo complexo. Certamente hoje eu vejo isso de uma forma totalmente diferente. Pra mim, hoje, escrever uma boa documentação - não apenas fluxos, mas também porque e como decisões foram tomadas - é algo muito importante no meu dia-a-dia. &lt;/p&gt;

&lt;p&gt;Nesse texto eu poderia falar sobre como manter, ou sobre como não tornar burocracias uma tarefa burocrática, mas acho que não é o meu propósito no momento. Acho que posso até pensar em fazer isso em um outro texto. &lt;/p&gt;

&lt;p&gt;Mas em um mundo com milhares de siglas como &lt;a href="https://adr.github.io/" rel="noopener noreferrer"&gt;ADR&lt;/a&gt;, &lt;a href="https://www.techtarget.com/whatis/definition/Request-for-Comments-RFC" rel="noopener noreferrer"&gt;RFC&lt;/a&gt;, &lt;a href="https://acqnotes.com/acqnote/acquisitions/preliminary-design-review" rel="noopener noreferrer"&gt;PDR&lt;/a&gt;, &lt;a href="https://writingcooperative.com/the-anatomy-of-an-amazon-6-pager-fc79f31a41c9" rel="noopener noreferrer"&gt;6-pager&lt;/a&gt;, &lt;a href="https://slidemodel.com/business-one-pager-examples/" rel="noopener noreferrer"&gt;1-page&lt;/a&gt;... ufa... não podemos deixar de pensar no básico como desenvolvedores: o bom e velho read-me escrito com o maravilhoso Markdown. &lt;/p&gt;

&lt;p&gt;Aqui vale lembrar que nenhuma dessas documentações será substituída pelo Read-me e nem que todas essas documentações serão usadas o tempo todo. Vamos lembrar que todas são ferramentas e ferramentas devem ser usadas pra resolver problemas específicos. &lt;/p&gt;

&lt;p&gt;Bom... Então vamos ao que interessa. O Read-me. &lt;/p&gt;

&lt;h2&gt;
  
  
  Twitter... fale comigo
&lt;/h2&gt;

&lt;p&gt;Eu já tentei diversos modelos de read-me's no passar dos anos e acho que isso é algo que sempre estará em mutação. Mas pra buscar não ser tão enviesado com meu gosto pessoal do que eu gostaria que tivesse nessa documentação, eu resolvi falar com a minha bolha... a famigerada bolha tech. E pra isso eu abri essa thread aqui no twitter. &lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1563254362402885637-461" src="https://platform.twitter.com/embed/Tweet.html?id=1563254362402885637"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1563254362402885637-461');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1563254362402885637&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;E com isso eu consegui entender o que as pessoas viam de valor no read-me de um projeto e com isso eu tentei consolidar o seguinte pros meus projetos (pessoais e da empresa).&lt;/p&gt;

&lt;h2&gt;
  
  
  Better read-me's
&lt;/h2&gt;

&lt;p&gt;Bom... aqui eu começo fazendo um apelo. Por favor... por favor meesmo... não deixem o projeto sem o mínimo de informação no Read-me ou com a documentação padrão gerada pelo framework que você tá usando. &lt;/p&gt;

&lt;p&gt;Feito esse apelo, vamos ao que interessa. &lt;/p&gt;

&lt;h3&gt;
  
  
  Comece pelo básico
&lt;/h3&gt;

&lt;p&gt;Algumas informações são essenciais para que as pessoas minimamente entendam o que o seu projeto está fazendo e deveriam estar em todo README como o mínimo aceitável. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O nome do projeto&lt;/li&gt;
&lt;li&gt;Uma breve descrição do projeto (mesmo que você repita isso no About do Github)&lt;/li&gt;
&lt;li&gt;E comandos importantes que possam ser executados no projeto. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Com esse mínimo, você vai tirar as pessoas da mais completa zona de escuridão e vai permitir que ela tenha um entendimento básico do escopo do projeto e vai saber o que ela precisa fazer pra rodar o projeto. &lt;/p&gt;

&lt;p&gt;Nesse contexto mínimo ainda vale adicionar uma área para dependências (sejam elas quais forem) para rodar/testar o projeto. &lt;/p&gt;

&lt;p&gt;Veja um exemplo de README enxuto aqui &lt;a href="https://gist.github.com/marcopollivier/7d4a378332f23d5c6302abc357848064#file-readme_minimo-md" rel="noopener noreferrer"&gt;https://gist.github.com/marcopollivier/7d4a378332f23d5c6302abc357848064#file-readme_minimo-md&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa4w5o0ru5i7515czfjbs.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa4w5o0ru5i7515czfjbs.jpg" alt="exemplo de readme basico" width="800" height="1260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Vá além do básico
&lt;/h3&gt;

&lt;p&gt;O modelo anterior é o mínimo que um projeto deveria ter. Nenhum projeto novo que será usado por outra pessoa - ou por você mesmo no futuro - deveria ter menos do que isso. &lt;/p&gt;

&lt;p&gt;Porém se você quiser ir um pouco mais além, existem outras informações que também não são complexas de manter e que proporcionarão um maior suporte ao seu projeto. São elas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Toda a lista anterior (obviamente);&lt;/li&gt;
&lt;li&gt;Principais funcionalidades &lt;/li&gt;
&lt;li&gt;Breve desenho da arquitetura (especialmente as principais integrações. Para esse ponto, recomendo fortemente utilizar a &lt;a href="https://github.blog/2022-02-14-include-diagrams-markdown-files-mermaid/" rel="noopener noreferrer"&gt;integração entre Github e Mermaid&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Características relevantes como latência, escalabilidade e segurança&lt;/li&gt;
&lt;li&gt;Links para documentações e links de referências &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzxinffv7d2tajgq3lvwa.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzxinffv7d2tajgq3lvwa.jpg" alt="Modelo de readme ok" width="800" height="1922"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  README campeão
&lt;/h3&gt;

&lt;p&gt;O modelo anterior já podemos entender que será um excelente apoio para quem está chegando no repositório pela primeira vez. Mas vale lembrar que com o advento dos micro-serviços, a gestão ficou muito mais granular e complexa de manter. Então, para um readme campeão, esse ponto precisa ser levado em conta. E para isso, busque chegar a esse modelo final, adicionado os seguintes tópicos ao anteriores: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O Contexto de criação do projeto/serviço&lt;/li&gt;
&lt;li&gt;Quais problemas tentam ser resolvidos &lt;/li&gt;
&lt;li&gt;O escopo do projeto (para qual finalidade ele foi pensado e o que ele NÃO vai atender) e&lt;/li&gt;
&lt;li&gt;Alternativas que poderiam ser usadas no lugar desse projeto e porque não foram usadas. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ah... use e abuse de tags como essas&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftm3m3ovcs11v1xp4g6mm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftm3m3ovcs11v1xp4g6mm.png" alt="Tags coloridas para serem usadas no readme" width="488" height="44"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Essas tags podem ser usadas tanto para métricas básicas como ferramentas para ajudar a criar links para documentações, boards e etc. &lt;/p&gt;

&lt;p&gt;No fim, seu README campeão vai ficar parecido com esse aqui &lt;a href="https://gist.github.com/marcopollivier/7d4a378332f23d5c6302abc357848064#file-readme_campeao-md" rel="noopener noreferrer"&gt;https://gist.github.com/marcopollivier/7d4a378332f23d5c6302abc357848064#file-readme_campeao-md&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs356q2l927k5wl942fey.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs356q2l927k5wl942fey.jpg" alt="Modelo de Readme campeão" width="800" height="2443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Considerações finais
&lt;/h1&gt;

&lt;p&gt;Escrever e manter uma boa documentação é tão importante quanto escrever e manter um bom código. Se você não faz um dos dois, existe a grande possibilidade de você também negligenciar o outro. Documentações são uma forma de você dar contexto histórico ao que estava acontecendo em um determinado momento para que pessoas no futuro entendam o motivo das decisões tomadas. Além de ser uma excelente ferramenta de performance. Isso mesmo que você escutou. As pessoas associam a criação de documentação como algo burocrático, tedioso e que toma tempo. Mas quando você escreve o mínimo (como mostrei aqui nesse texto), as próximas pessoas que precisarem entender, ganharão um tempo absurdo no entendimento do que o projeto ou serviço se propõe. Escrever documentação faz parte da rotina de um bom Engenheiro de Softwares. Escrever documentação faz parte do processo de amadurecimento de qualquer profissional. &lt;/p&gt;

&lt;h2&gt;
  
  
  Leia mais sobre documentação
&lt;/h2&gt;

&lt;p&gt;Lembram que eu abri a thread no Twitter? Então... algumas pessoas maravilhosas compartilharam links de artigos interessantes e vou facilitar a vida de vocês listando aqui &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.pplupo.com/2022-01-08-Software-Documentation-is-Software/" rel="noopener noreferrer"&gt;Software Documentation is software&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/tech-will/como-mantemos-as-docs-completas-simplificadas-e-atualizadas-no-will-bank-d6cbd639197b" rel="noopener noreferrer"&gt;Como mantemos as docs completas, simplificadas e atualizadas no Will Bank&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/edsoncelio/7c00f1f6ba998db4d2ab778c4932a03b#readmes" rel="noopener noreferrer"&gt;Notes about docs for developers book&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>documentacao</category>
      <category>readme</category>
      <category>markdown</category>
      <category>boaspraticas</category>
    </item>
    <item>
      <title>Gerencie suas versões Go com GVM</title>
      <dc:creator>Marco Ollivier</dc:creator>
      <pubDate>Tue, 25 Aug 2020 22:42:56 +0000</pubDate>
      <link>https://forem.com/marcopollivier/gerencie-suas-versoes-go-com-gvm-4m1f</link>
      <guid>https://forem.com/marcopollivier/gerencie-suas-versoes-go-com-gvm-4m1f</guid>
      <description>&lt;p&gt;Ganhe produtividade gerenciando as versões Go na sua máquina de forma simples usando o GVM&lt;/p&gt;

&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;A configuração de um ambiente de desenvolvimento Go pode ser um pouco confusa para quem está acostumado a trabalhar com outras linguagens. Quando estamos falando de versões do Go inferiores a 1.11, o cenário ainda pode se tornar mais chato devido suas peculiaridades (que não serão abordadas nesse momento, mas quem já precisou, sabe do que se trata).&lt;/p&gt;

&lt;p&gt;Como de padrão no mundo Go, a &lt;a href="https://golang.org/doc/install" rel="noopener noreferrer"&gt;documentação oficial&lt;/a&gt; traz uma solução que se mostra relativamente fácil, bem clara e objetiva; e que, inclusive, fala sobre a questão de ter mais de uma versão do Go instalada ao mesmo tempo.&lt;/p&gt;

&lt;p&gt;veja mais sobre como configurar o seu ambiente na &lt;a href="https://golang.org/doc/install" rel="noopener noreferrer"&gt;Documentação Oficial Golang&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mesmo assim, o gerenciamento é um trabalho manual que exige uma quantidade grande de passos e que tende a ficar mais complicada dependendo da quantidade de versões instaladas que você possui.&lt;br&gt;
O chaveamento entre versões também pode ser um problema quando você possuir diferentes projetos no seu workspace que estejam em fases de maturidade diferentes. Se você tem projetos antigos em uma determinada versão, mas quer escrever um novo com uma versão mais atual, isso também pode ser um processo trabalhoso.&lt;br&gt;
Pensando em diminuir essa complexidade e melhorar o gerenciamento de versões, surgiu o &lt;a href="https://github.com/moovweb/gvm" rel="noopener noreferrer"&gt;GVM&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Admito que me preocupo um pouco em escrever sobre uma ferramenta que não tem recebido commits recentes (enquanto escrevo esse texto, tem 1 ano desde o último commit), mas como ele ainda tem se mostrado uma ferramenta relativamente útil no meu dia-a-dia, prefiro apostar na recomendação.&lt;br&gt;
Note que algumas outras linguagens já possuem ferramentas que fazem um trabalho similar. É o caso, por exemplo, do &lt;a href="https://github.com/nvm-sh/nvm" rel="noopener noreferrer"&gt;NVM&lt;/a&gt; para o gerenciamento de versões Node.JS.&lt;/p&gt;
&lt;h2&gt;
  
  
  Ambiente
&lt;/h2&gt;

&lt;p&gt;É importante frisar antes de mais nada que estamos fazendo todo esse processo em um ambiente Linux. Mais precisamente para esse exemplo estamos utilizando a Versão 18.04.2 LTS do Ubuntu, mas já fiz o mesmo procedimento em um ambiente MacOS e funciona tão bem quanto.&lt;/p&gt;
&lt;h2&gt;
  
  
  Instalação
&lt;/h2&gt;

&lt;p&gt;Para instalar execute o seguinte comando de acordo com o seu interpretador shell.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bash
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bash &amp;lt; &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-S&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt; https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;ZSH
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;zsh &amp;lt; &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-S&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt; https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Esse comando irá gerar uma &lt;strong&gt;.gvm&lt;/strong&gt; dentro da sua home. Mo meu caso, a pasta foi criada em &lt;strong&gt;~/.gvm&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsqtuuj1uv09q5pnf51su.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsqtuuj1uv09q5pnf51su.png" alt="Retorno no terminal que será exibido após executar o comando anterior" width="655" height="117"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Restarte o terminal e execute o comando &lt;code&gt;gvm version&lt;/code&gt; para confirmar que a instalação foi efetuada com sucesso.&lt;br&gt;
Eventualmente pode acontecer de algumas dependências não estarem instaladas. Por exemplo, no ambiente que estou usando como base para esse texto, ainda faltava instalar algumas dependências.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzoq97c7mbr7aqmjhkgs0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzoq97c7mbr7aqmjhkgs0.png" alt="Dependências faltando" width="298" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Com as dependências devidamente instaladas, executamos novamente o comando &lt;code&gt;gvm version&lt;/code&gt; e teremos o seguinte retorno.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnf1cq4s2yzgocmcn158t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnf1cq4s2yzgocmcn158t.png" alt="Versão instalada" width="552" height="23"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note que para que o comando gvm seja identificado pelo Sistema Operacional, uma nova linha foi adicionada dentro do seu arquivo &lt;strong&gt;bashrc&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Instalando Go
&lt;/h2&gt;

&lt;p&gt;Agora vamos efetivamente instalar as versões que queremos ter como opções no nosso ambiente. Nesse caso, vamos instalar as versões 1.10 e a 1.11, sendo a última como nossa versão padrão. Para isso, basta executar os seguintes comandos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gvm &lt;span class="nb"&gt;install &lt;/span&gt;go1.10 &lt;span class="nt"&gt;-B&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;gvm &lt;span class="nb"&gt;install &lt;/span&gt;go1.11 &lt;span class="nt"&gt;-B&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Para a versão 1.11 como padrão, execute:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gvm use go1.11 &lt;span class="nt"&gt;--default&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Para validar, liste as versões instaladas por meio do comando:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gvm list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Você terá o seguinte retorno&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F656vtuwb7h82iiz5oc7p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F656vtuwb7h82iiz5oc7p.png" alt="Versões instaladas do Go" width="190" height="90"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feito isso já teremos nosso ambiente pronto para uso e as variáveis de ambiente &lt;strong&gt;$GOROOT&lt;/strong&gt; e &lt;strong&gt;$GOPATH&lt;/strong&gt; já foram configuradas automaticamente. Por padrão são definidos nos caminhos:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#GOPATH&lt;/span&gt;
~/.gvm/pkgsets/go1.11/global
&lt;span class="c"&gt;#GOROOT&lt;/span&gt;
~/.gvm/gos/go1.11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Validando
&lt;/h2&gt;

&lt;p&gt;Feito todo esse processo de instalação, a forma que usamos o Go no nosso ambiente não deve ser influenciada. Então vamos validar o que fizemos. Para isso, vamos criar um Hello.go com o seguinte código.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello, world&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;E aí está…. verificamos que a versão instalada é a que selecionamos e também que nosso código foi executado com sucesso.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F01yw4r1ljwkr1fonv5lx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F01yw4r1ljwkr1fonv5lx.png" alt="Sucesso" width="324" height="93"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Mesmo a documentação mostrando que pode ser relativamente simples manter mais de uma versão instalada ao mesmo tempo de forma “nativa”, gastar tempo configurando ambiente é uma coisa que ninguém gosta e o GVM se mostra eficiente nesse aspecto. Instalar uma nova versão e chavear entre elas se mostra uma tarefa muito menos custosa usando esse gerenciador de versões. E você, o que achou? Deixe seu comentário e até a próxima.&lt;/p&gt;



&lt;p&gt;Gostou do &lt;a href="https://github.com/moovweb/gvm" rel="noopener noreferrer"&gt;GVM&lt;/a&gt;.? Leia mais detalhes na documentação oficial no Github&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/moovweb" rel="noopener noreferrer"&gt;
        moovweb
      &lt;/a&gt; / &lt;a href="https://github.com/moovweb/gvm" rel="noopener noreferrer"&gt;
        gvm
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Go Version Manager
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;gvm&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://travis-ci.org/moovweb/gvm" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/decee637b4501a8366bce625acb6a0843f0dac30a19be3e711f74e7df728018c/68747470733a2f2f7472617669732d63692e6f72672f6d6f6f767765622f67766d2e7376673f6272616e63683d6d6173746572" alt="Build Status"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By Josh Bussdieker (jbuss, jaja, jbussdieker) while working at &lt;a href="https://www.moovweb.com" rel="nofollow noopener noreferrer"&gt;Moovweb&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Currently lovingly maintained by &lt;a href="https://github.com/BenKnigge" rel="noopener noreferrer"&gt;Benjamin Knigge&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pull requests and other any other contributions would be very much appreciated.&lt;/p&gt;

&lt;p&gt;GVM provides an interface to manage Go versions.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Features&lt;/h1&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Install/Uninstall Go versions with &lt;code&gt;gvm install [tag]&lt;/code&gt; where tag is "60.3", "go1", "weekly.2011-11-08", or "tip"&lt;/li&gt;
&lt;li&gt;List added/removed files in GOROOT with &lt;code&gt;gvm diff&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Manage GOPATHs with &lt;code&gt;gvm pkgset [create/use/delete] [name]&lt;/code&gt;. Use &lt;code&gt;--local&lt;/code&gt; as &lt;code&gt;name&lt;/code&gt; to manage repository under local path (&lt;code&gt;/path/to/repo/.gvm_local&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;List latest release tags with &lt;code&gt;gvm listall&lt;/code&gt;. Use &lt;code&gt;--all&lt;/code&gt; to list weekly as well.&lt;/li&gt;
&lt;li&gt;Cache a clean copy of the latest Go source for multiple version installs.&lt;/li&gt;
&lt;li&gt;Link project directories into GOPATH&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Background&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;When we started developing in Go mismatched dependencies and API changes plagued our build process and made it extremely difficult to merge with other peoples changes.&lt;/p&gt;

&lt;p&gt;After nuking my entire GOROOT several times and…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/moovweb/gvm" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;
 

</description>
      <category>go</category>
      <category>gvm</category>
    </item>
  </channel>
</rss>
