<?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>DEV Community: Marcelo Matz</title>
    <description>The latest articles on DEV Community by Marcelo Matz (@matzcoelho).</description>
    <link>https://dev.to/matzcoelho</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%2F766247%2F5d38ae4b-9862-4fc5-89e0-7ee9af6f624a.jpeg</url>
      <title>DEV Community: Marcelo Matz</title>
      <link>https://dev.to/matzcoelho</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/matzcoelho"/>
    <language>en</language>
    <item>
      <title>Carreira Dev: Não comece pelo frontend</title>
      <dc:creator>Marcelo Matz</dc:creator>
      <pubDate>Mon, 11 Sep 2023 17:37:59 +0000</pubDate>
      <link>https://dev.to/matzcoelho/carreira-dev-nao-comece-pelo-frontend-4c34</link>
      <guid>https://dev.to/matzcoelho/carreira-dev-nao-comece-pelo-frontend-4c34</guid>
      <description>&lt;p&gt;Está começando agora ou pensando em começar na carreira DEV, então toma aqui o primeiro ensinamento: &lt;strong&gt;a carreira dev vai comer o teu rabo sem dó!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chorume inicial
&lt;/h2&gt;

&lt;p&gt;De uns anos pra cá, encontrar um vendedor de curso falando em jornada de carreira dev frontend mobile ultra blaster se tornou a coisa mais comum.&lt;/p&gt;

&lt;p&gt;O problema é uns 80% desses são picaretas e os outros 20% estão sendo esmagados pelo marketing dos trambiqueiros.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Encontrar curso bom se tornou mais difícil do que achar dev especialista em Phonegap.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Alguns cursos acabam mostrando somente uma camada, dentre tantas que existem, dentro do mundo do desenvolvimento e deixam de lado uma imensidão de oportunidades de carreira.&lt;/p&gt;

&lt;p&gt;Apesar do título deste post parecer tendencioso, e é, você vai perceber que o meu objetivo aqui não é brigar com o frontend ou com os vendedores de cursos, muito pelo contrário, você vai encontrar uma visão realista do que a gente sabe que está acontecendo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Disclaimer: eu não vendo ou recomendo curso de ninguém. O que você vai encontrar aqui é a opinião de alguém que está desde o ano 2000 vivendo do mercado de tecnologia.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Começando na carreira Dev
&lt;/h2&gt;

&lt;p&gt;Começar na carreira Dev tem se tornado um desafio enorme pra muita gente. Parte dessas pessoas são acometidas por tantas ofertas de cursos, imersões, semanas de aprendizado profundo, técnicas inovadoras de aprender linguagens de programação em 7 dias, etc!&lt;/p&gt;

&lt;p&gt;Na real, o problema não é as pessoas venderem cursos. O problema é vender mentiras.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vamos falar sobre 4 contos do vigário:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1º - Não tem centenas de milhares de vagas de emprego.&lt;/strong&gt;&lt;br&gt;
Hoje, inclusive, o que mais tem são pessoas de tecnologia procurando vagas, logo, vai conseguir uma oportunidade quem se destacar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2º - Não é todo mundo que vai conseguir.&lt;/strong&gt;&lt;br&gt;
Tem gente que começa, tenta, se esforça e não consegue. Começar é fácil, mas isso é assim em qualquer coisa. Difícil é conseguir persistir.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3º - Você não vai aprender a programar em 7 dias!&lt;/strong&gt;&lt;br&gt;
Você até pode aprender a datilografar código e vai aprender um básico do básico, mas isso não vai te levar para o próximo nível.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4º - Não caia no conto da melhor linguagem de programação.&lt;/strong&gt;&lt;br&gt;
Se você ver um vídeo de um vendedor de curso de Python, ele vai te mostrar que Python é a linguagem mais usada no mundo. Se for um vendedor de curso de Javascript, ele vai fazer a mesma coisa e assim todos os outros.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O que é verdade na carreira dev é:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Não existe salário alto pra quem tá começando;&lt;/li&gt;
&lt;li&gt;Existem casos raros e excessões que ganham muito, e elas serão apresentadas à você como um troféu;&lt;/li&gt;
&lt;li&gt;Tem escolas sérias de tecnologia que te ensinam habilidades técnicas, de negócios e de relacionamento, mas são poucas;&lt;/li&gt;
&lt;li&gt;Você não vai sair de uma imersão sabendo programar. Você no máximo aprender a copiar código escrito por outra pessoa;&lt;/li&gt;
&lt;li&gt;Você só vai aprender a programar, programando. Quando você parar de repetir tutorial e começar a fazer os seus próprios, você aprende;&lt;/li&gt;
&lt;li&gt;Altos salários existem sim e você pode ter um. Trabalhe por ele e foque na sua carreira, dedique anos estudando para ser bom no que você faz que o reconhecimento financeiro vem;&lt;/li&gt;
&lt;li&gt;A maioria das vagas de emprego vão dizer uma coisa e na prática você vai fazer outra. Lide com isso desde agora ou viva reclamando depois.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Por onde começar?
&lt;/h2&gt;

&lt;p&gt;Desde o início da pandemia até agora, o que mais apareceu no mercado foi desenvolvedor vendendo cursos. Cada pessoa/escola tenta puxar a farinha para o seu saco, afinal de contas a gente está falando de um segmento de mercado chamado Educação.&lt;/p&gt;

&lt;p&gt;Como subcategoria de educação, temos o ensino de tecnologia. Dentro de tecnologia tem uma caralhada de coisas que não cabem aqui neste post.&lt;/p&gt;

&lt;p&gt;Quanto mais específico for o curso que você estiver fazendo, mais distante você acaba ficando de outras tecnologias.&lt;/p&gt;

&lt;p&gt;A minha recomendação para você que está começando agora na carreira de dev é primeiro andar por algumas áreas e entender como cada uma funciona, o mercado de trabalho, as pessoas que fazem parte deste meio, a forma de atuação das empresas que contratam pessoas para essa área e a sua participação dentro do mundo da tecnologia a partir deste ponto de vista.&lt;/p&gt;

&lt;p&gt;Perceba que se você conseguir experimentar um pouco de cada área, isso no fim das contas só vai te ajudar a enxergar que existe mais coisas além dos limites apresentados dentro dos cursinhos que você vai encontrar por aí.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dedo na ferida do frontend
&lt;/h2&gt;

&lt;p&gt;A oferta de cursos de frontend usando Javascript, React, Angular, etc, vem aumentando muito.&lt;/p&gt;

&lt;p&gt;Tão enfiando JS em tudo. E tudo bem, mas nem tão bem assim!&lt;/p&gt;

&lt;p&gt;O uso do Javascript aumentou muito com o surgimento de bibliotecas e frameworks, o que acaba atraindo a atenção das pessoas, empresas e consequentemente dos vendedores de cursos.&lt;/p&gt;

&lt;p&gt;Vende-se uma imagem de que, se você começar pelo frontend, por ele ser a camada da web onde as pessoas mais interagem, acaba sendo mais acessível e fácil expor um portfólio para então, a partir disso, conseguir uma vaga de emprego. &lt;em&gt;E isso não é mentira, mas também não é totalmente verdade.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Escolher começar pelo frontend pode ser tentador e fazer todo sentido, visto que é uma área que cresce muito, tem grande oferta de cursos, muitas empresas focadas em vender formações frontend, mas por outro lado pode ser o começo de um caminho extenso, cansativo e extremamente ruim para algumas pessoas.&lt;/p&gt;

&lt;p&gt;O desenvolvimento de software vai além da criação de interfaces, apps, sites, landing-pages ou qualquer outra coisa que se crie a partir do frontend hoje em dia.&lt;/p&gt;

&lt;p&gt;O desenvolvimento híbrido de aplicativos pode até ser um bom mercado, mas entrar nele sem nem conhecer o desenvolvimento nativo, por exemplo, pode ser uma furada.&lt;/p&gt;

&lt;p&gt;Vamos pelo caminho da lógica:&lt;br&gt;
Uma pessoa que começa pelo frontend vai seguir basicamente uma jornada onde ela começa aprendendo HTML, CSS e o básico de Javascript e depois vai aprofundando em JS até ser imersa em alguma ramificação. &lt;/p&gt;

&lt;p&gt;Essa ramificação vai acabar chegando num React da vida que hoje em dia é a biblioteca mais hypada.&lt;/p&gt;

&lt;p&gt;É normal aparecer aqueles anúncios assim: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Seja um desenvolvedor mobile e conquiste a liberdade de ser um nômade digital, ganhar altos salários em dólar e conquistar a sua tão sonhada liberdade financeira 🤡&lt;br&gt;
O vendedor de curso de Javascript vai te dizer que se você aprender apenas Javascript, você vai desenvolver software para qualquer tipo de dispositivo e ainda vai te mostrar exemplos de APPs que foram feitos em JS.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O que não te contam é que essa jornada vai muito além, e que chega um momento onde a pessoa focou tanto em uma determinada tecnologia, que ela acabou deixando de lado o aprendizado em programação para se tornar especialista em biblioteca.&lt;/p&gt;

&lt;p&gt;Ao invés da pessoa aprender Javascript e trabalhar com JS, ela aprende React para usar NextJS ou outro framework da modinha, e depois fica horas e horas estudando algum framework de CSS para criar estilos, e por aí vai.&lt;/p&gt;

&lt;p&gt;Aí chega a hora de colocar o APP no ar e a pessoa aprende a fazer deploy de APP feito em cima de framework. Nunca viu dentro do curso uma linha de informação sobre redes, protocolos, etc, mas vai aprender a seguir um tutorial de como integrar um CI/CD na Vercel a partir de um repositório no GitHub.&lt;/p&gt;

&lt;p&gt;O que até aqui parece uma crítica, é na verdade um alerta.&lt;/p&gt;

&lt;p&gt;A gente precisa parar de romantizar a carreira de desenvolvimento e mostrar que o campo de atuação é muito maior e ele vai além do hype da web.&lt;/p&gt;

&lt;p&gt;Tecnologias embarcadas, softwares desktop, iOT, ciência de dados, banco de dados, hardware, games, carros autônomos, aviação comercial, agro pop e diversos outros meios precisam de pessoas desenvolvedoras para criar softwares que não chegam nem perto de rodar na web.&lt;/p&gt;

&lt;h2&gt;
  
  
  Se liga nisso aqui 👇
&lt;/h2&gt;

&lt;p&gt;O que eu já vi de frameworks morrerem nos últimos 25 anos não foi pouco, e isso não vai acabar. &lt;/p&gt;

&lt;p&gt;Um exemplo prático disso &lt;strong&gt;eu mesmo vivenciei&lt;/strong&gt; quando, em 2002 eu fiz algumas especializações em Flash, uma tecnologia que na época era considerada a coisa mais incrível já criada no mundo e que pouco tempo depois viria a ser totalmente destruída.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Quem tem 30+ vai lembrar que foi Steve Jobs e o iPhone que decretaram o fim da vida do então Adobe Flash.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Não caia nas garras do framework bandido
&lt;/h2&gt;

&lt;p&gt;Pare de programar orientado à framework, ou nem comece a programar assim se você ainda não sentiu esse gostinho.&lt;/p&gt;

&lt;p&gt;É tipo sangue em boca de vampiro.&lt;/p&gt;

&lt;p&gt;Não que eles (os frameworks, não os vampiros) não sejam importantes, mas você precisa aprender algumas coisas antes de usar frameworks. &lt;/p&gt;

&lt;p&gt;Se lá em 2000 quando eu comecei a focar mais em desenvolvimento eu não tivesse ampliado o meu campo de atuação e conhecimento, aprendendo Linux, banco de dados, redes e infraestrutura, eu não teria conseguido os empregos que eu consegui e muito menos teria a experiência que eu tenho hoje.&lt;/p&gt;

&lt;h2&gt;
  
  
  Se liga que Programação é diferente de Desenvolvimento
&lt;/h2&gt;

&lt;p&gt;Programar e desenvolver são coisas que podem ser semelhantes e podem também ser completamente diferentes.&lt;/p&gt;

&lt;p&gt;Programar é o ato de entender e saber usar as linguagens de programação.&lt;/p&gt;

&lt;p&gt;Desenvolver é usar a programação para construir algo. &lt;/p&gt;

&lt;p&gt;Esse algo pode ser tanto uma coisa (software) pequeno e simples como também pode ser algo grandioso e complexo.&lt;/p&gt;

&lt;p&gt;Dentro do desenvolvimento de software, por exemplo, nós temos diversos outros profissionais além da pessoa dev trabalhando no projeto.&lt;/p&gt;

&lt;p&gt;O que os (alguns) cursos de dev tentam fazer é &lt;em&gt;encurtar a jornada&lt;/em&gt; e "preparar o profissional para o mercado de trabalho" no menor tempo possível.&lt;/p&gt;

&lt;p&gt;O que acaba sendo uma merda!&lt;/p&gt;

&lt;p&gt;Diferente de uma graduação, por exemplo, onde a ideia é entrar a fundo em campos de estudos e fazer isso ao decorrer de alguns anos, os cursos removem do treinamento tudo aquilo que eles consideram desnecessário.&lt;/p&gt;

&lt;p&gt;Exemplo são os cursos que ensinam a salvar dados num banco de dados, mas a pessoa que aprende não tem a menor noção do motivo de ela estar usando MongoDB ao invés de mySQL, por exemplo, ou qualquer outra solução no lugar outra solução, não importa.&lt;/p&gt;

&lt;p&gt;Na minha humilde opinião, o que falta hoje são os cursos assumirem que o que eles ensinam é apenas uma parcela do que é necessário saber.&lt;/p&gt;

&lt;p&gt;Alguns poucos falam que você precisa ir além, etc, etc, etc, mas poucos mostram o caminho.&lt;/p&gt;

&lt;p&gt;Algumas escolas de formação até possuem planos de carreira que contemplam diversos cursos e formações, onde no final de tudo isso a pessoa, teoricamente, é especialista em alguma coisa.&lt;/p&gt;

&lt;p&gt;Naturalmente, se você começar a estudar uma tecnologia hoje, em poucos dias você vai topar com 200 novas tecnologias que estão envolvidas no meio do caminho dentro do pouco que você está usando.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Começa instalando o editor de código, aprendendo que precisa digitar comandos em um terminal, descobre que vai ter que usar Linux, entende que para "facilitar" criaram alguns pacotes que você só vai instalar e sair usando, etc, etc, etc.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Toda jornada de tecnologia começa simples e termina caótica. &lt;/p&gt;

&lt;p&gt;Quando você acha que está sabendo muito e que manja dos paranauê de desenvolver, você descobre que precisa aprender algoritmos, estruturas de dados, descobre que existem paradigmas de programação, começa a acumular livros cansativos e chatos como os do Uncle Bob, Eric Evans e Martin Fowler, tendo que ler traduções grotescas de obras que só fazem sentido quando você conhece um campo muito mais amplo no desenvolvimento de software.&lt;/p&gt;

&lt;p&gt;Em pouco tempo você vai ter uma lista de tecnologias tão grande para estudar e vai ver que outras pessoas estão muito mais avançadas do que você, e então você começa a se sentir menos capaz, começa a enxergar as oportunidades mais distantes, sente que dentro da própria comunidade de desenvolvimento existe muito mais um jogo de egos do que uma estrutura para ajudar quem está começando e começa a pensar em desistir.&lt;/p&gt;

&lt;p&gt;Não se deixe abalar pelo caminho percorrido pelos outros. Foque em você! E esse é o melhor conselho que qualquer pessoa pode te dar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Não se limite
&lt;/h2&gt;

&lt;p&gt;No fim das contas a mensagem que eu quero te passar é: não se limite. &lt;/p&gt;

&lt;p&gt;Não deixe a guerrinha entre linguagens de programação te fazer desistir ou persistir somente em um caminho a partir da opinião de outros. Experimente você mesmo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O que você não deve experimentar são drogas. Linguagens de programação você pode testar todas.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Explore, conheça, teste linguagens de programação, mesmo aquelas que você olha para a sintaxe do código e pensa: isso aqui não foi feito por humanos.&lt;/p&gt;

&lt;p&gt;Existem diversos tutoriais passo a passo no YouTube que podem te ajudar a ver mais conceitos. Não é porque você vai trabalhar com uma linguagem orientada à objetos que você vai deixar e entender sobre programação funcional, ou procedural, por exemplo.&lt;/p&gt;

&lt;p&gt;Quando você entende mais sobre diferentes linguagens, você começa a perceber que as todas elas meio que são iguais, e que independente da linguagem que você tem mais domínio, saber programação te habilita a aprender outras linguagens rapidamente.&lt;/p&gt;

&lt;p&gt;Saber programação não é sobre dominar uma linguagem de programação por completo e saber tudo o que pode ser feito com ela. Programação é saber quando e onde usar determinada linguagem e aplicar ela para resolver o problema que tiver que ser resolvido.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;E isso não quer dizer que ser generalista é melhor do que ser especialista&lt;/strong&gt;, mas se você começar do zero e colocar o objetivo de ser especialista em uma coisa sem nem conhecer as outras antes, pode ser que ali na frente você descubra que a sua escolha poderia ter sido melhor, ou não.&lt;/p&gt;

&lt;p&gt;Espero você no próximo post. Até lá.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>programming</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Google Places API: criando um App em Go para testar o novo recurso de Text Search</title>
      <dc:creator>Marcelo Matz</dc:creator>
      <pubDate>Tue, 05 Sep 2023 17:25:35 +0000</pubDate>
      <link>https://dev.to/matzcoelho/google-places-api-criando-um-app-em-go-para-testar-o-novo-recurso-de-text-search-2jc1</link>
      <guid>https://dev.to/matzcoelho/google-places-api-criando-um-app-em-go-para-testar-o-novo-recurso-de-text-search-2jc1</guid>
      <description>&lt;p&gt;Eu recentemente coloquei um desafio no meio das minhas metas: &lt;strong&gt;implementar uma aplicação fullstack usando a linguagem de programação Go&lt;/strong&gt;. E eu consegui 🤘&lt;/p&gt;

&lt;p&gt;Este artigo é sobre &lt;strong&gt;a minha experiência&lt;/strong&gt; implementando &lt;a href="https://developers.google.com/maps/documentation/places/web-service/text-search?hl=pt-br" rel="noopener noreferrer"&gt;um novo recurso da API&lt;/a&gt; de Places do Google Maps usando &lt;strong&gt;Go no backend e JS no frontend&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Se você quer uma versão resumida e em vídeo deste artigo, &lt;a href="https://www.youtube.com/embed/sZOXibnGP5E?si=CFJFexMQZFmQgfvB" rel="noopener noreferrer"&gt;aqui você encontra&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Depois da &lt;a href="https://dev.to/marcelomatz/poc-evoluindo-o-busca-cep-com-ddd-e-clean-code-389"&gt;PoC do BuscaCep usando DDD e CleanCode&lt;/a&gt; onde eu usei a API do ViaCep, eu comecei a pesquisar mais sobre o assunto e obviamente eu acabei esbarrando na plataforma do Google Maps.&lt;/p&gt;

&lt;p&gt;Neste artigo eu mostro passo a passo o que eu fiz para implementar o App, qual foi a linha de raciocínio que eu usei para criar cada coisa e ainda mostro o código que eu usei, tanto no backend quanto no frontend.&lt;/p&gt;




&lt;h2&gt;
  
  
  Google Maps
&lt;/h2&gt;

&lt;p&gt;O Google Maps é a plataforma do Google que te permite criar apps usando todas as informações que o Google tem sobre endereços.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Só o aprendizado para entender como o Google Maps é segmentado e principalmente como é feita a cobrança do serviço, já foi um baita aprendizado.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;A plataforma do Google Maps é dividida em três segmentações diferentes&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maps&lt;/li&gt;
&lt;li&gt;Routes&lt;/li&gt;
&lt;li&gt;Places
&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1dzhvi0oed9i4ar84kj.png" alt="Image Segmentação das APIs do Google Maps" width="800" height="311"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Maps é a API responsável por:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mapas estáticos&lt;/strong&gt;: &lt;em&gt;Mostre um mapa estático no seu site.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Imagens do Street View&lt;/strong&gt;: &lt;em&gt;Adicione imagens do Street View em 360° aos seus apps.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mapas de Elevação de terreno&lt;/strong&gt;: &lt;em&gt;Conseguir os dados da elevação de um ou vários locais.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Routes é a API responsável por:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;API Routes&lt;/strong&gt;: &lt;em&gt;Versão otimizada para a performance das APIs Directions e Distance Matrix com recursos extras.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Roads&lt;/strong&gt;: &lt;em&gt;Identifique vias próximas usando as coordenadas.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rotas&lt;/strong&gt;: &lt;em&gt;Forneça rotas para vários meios de transporte, com informações do trânsito em tempo real.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Matriz de distância&lt;/strong&gt;: &lt;em&gt;Calcule os tempos de viagem e as distâncias para várias origens e destinos.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Places é a API responsável por:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;API Places&lt;/strong&gt;: &lt;em&gt;Integre o Place Details, Search e Autocomplete do Google aos seus apps.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geocodificação&lt;/strong&gt;: &lt;em&gt;Converta coordenadas em endereços e vice-versa.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geolocalização&lt;/strong&gt;: &lt;em&gt;Veja a localização aproximada do dispositivo usando as torres de celular e os nós da rede Wi-Fi próximos.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Address Validation&lt;/strong&gt;: _Valide um endereço e seus componentes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fusos horários&lt;/strong&gt;: Descubra o fuso horário de um conjunto de coordenadas._&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  API Places
&lt;/h3&gt;

&lt;p&gt;Dentro dessa infraestrutura de APIs do Maps, o meu projeto se limitou a implementar a &lt;strong&gt;API Places&lt;/strong&gt; que é justamente a API que integrar o &lt;code&gt;Place Details&lt;/code&gt;, o &lt;code&gt;Search&lt;/code&gt; e também o &lt;code&gt;Autocomplete&lt;/code&gt; que eu não usei neste projeto.&lt;/p&gt;

&lt;p&gt;A aplicação foi dividida em 2 partes: &lt;strong&gt;backend&lt;/strong&gt; e &lt;strong&gt;frontend&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;objetivo principal&lt;/strong&gt; era implementar a parte de backend da API de Places usando o Search e o Place Details usando a linguagem Go, &lt;em&gt;sem deixar de criar um frontzinho básico&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Parte 1: &lt;strong&gt;Backend&lt;/strong&gt;&lt;br&gt;
A aplicação backend foi escrita em Go, e o papel desse backend era prover uma API que fosse responsável por buscar informações do Google Places API para depois retornar elas para o frontend. &lt;em&gt;Ao meu ver esse este é básico de uma aplicação web, hoje em dia.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alguns recursos do backend em Go&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Buscar lugares através da Google Places API&lt;/li&gt;
&lt;li&gt;Manejar CORS (isso consumiu algumas horas de estudo)&lt;/li&gt;
&lt;li&gt;Servir as informações obtidas para o frontend&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Como a API do Google Place exige que eu faça duas requisições, uma para buscar o local e outra para buscar os detalhes deste local, eu fiz uma implementação da seguinte forma:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Função &lt;strong&gt;SearchPlace&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;searchPlace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&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;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;PlaceSearch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;searchURL&lt;/span&gt; &lt;span class="o"&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;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://maps.googleapis.com/maps/api/place/textsearch/json?query=%s&amp;amp;key=%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryEscape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;gcpToken&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;client&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="n"&gt;searchURL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadCloser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;err&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&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;err&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="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="n"&gt;respBody&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAll&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;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;placeSearch&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;PlaceSearch&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;respBody&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;placeSearch&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;placeSearch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Ela tem a função de realizar uma consulta de pesquisa na API do Google Places, utilizando o termo de pesquisa fornecido como argumento &lt;code&gt;query&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;A chamada HTTP para a API é feita e a resposta (um JSON) é desserializada num objeto &lt;code&gt;PlaceSearch&lt;/code&gt;, que contém um &lt;em&gt;array de resultados&lt;/em&gt;, cada um com um &lt;code&gt;PlaceId&lt;/code&gt; correspondente. &lt;/p&gt;

&lt;p&gt;Se ocorrer um erro durante a execução da chamada HTTP ou durante a desserialização do JSON, o erro será retornado. Caso contrário, a função retorna o objeto &lt;code&gt;PlaceSearch&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Função &lt;strong&gt;getPlaceDetail&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;getPlaceDetail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&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;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;placeId&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;PlaceDetail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;detailURL&lt;/span&gt; &lt;span class="o"&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;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://maps.googleapis.com/maps/api/place/details/json?place_id=%s&amp;amp;fields=name,formatted_address,formatted_phone_number,website,rating,business_status,opening_hours,reviews,url,price_level&amp;amp;key=%s&amp;amp;language=pt-BR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;placeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gcpToken&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;client&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="n"&gt;detailURL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadCloser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;err&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&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;err&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="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="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAll&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;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;placeDetail&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;PlaceDetail&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;placeDetail&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;placeDetail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Essa função é utilizada para obter detalhes de um local específico, identificado pelo seu &lt;code&gt;PlaceId&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;A função faz uma chamada HTTP para um endpoint diferente da API do Google Places, que retorna os detalhes do local. &lt;/p&gt;

&lt;p&gt;A resposta (um JSON) é desserializada num objeto &lt;code&gt;PlaceDetail&lt;/code&gt;, que contém várias informações, incluindo nome, endereço formatado, URL do website, horário de funcionamento, reviews e mais. &lt;/p&gt;

&lt;p&gt;Da mesma forma que &lt;code&gt;searchPlace&lt;/code&gt;, se ocorrer um erro durante a chamada HTTP ou na desxerialização do JSON, o erro será retornado. Caso contrário, a função retorna o objeto &lt;code&gt;PlaceDetail&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As duas funções desempenham um papel crucial na interação com a API do Google Places - a searchPlace é utilizada para fazer consultas de busca gerais, enquanto a getPlaceDetail é utilizada para obter detalhes mais específicos sobre cada local retornado pela pesquisa.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Função &lt;strong&gt;searchHandler&lt;/strong&gt;
Essa função é o coração deste software.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;searchHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&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;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&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;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&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;Client&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Timeout&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;searchStr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;()&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;"query"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;placeSearch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;searchPlace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;searchStr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&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;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;totalPlaces&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;placeSearch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;details&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;PlaceDetail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;totalPlaces&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;placeSearch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Results&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;placeId&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&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;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getPlaceDetail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;placeId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&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;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;
        &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PlaceId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&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;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&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;A função &lt;code&gt;searchHandler&lt;/code&gt; é um manipulador HTTP que é acionado quando o endpoint /search é acessado.&lt;/p&gt;

&lt;p&gt;No começo da função, um cliente HTTP com um limite de tempo de 10 segundos é criado. Em seguida, ela extrai a string de pesquisa a partir da query do request HTTP.&lt;/p&gt;

&lt;p&gt;O método &lt;code&gt;searchPlace&lt;/code&gt; é então chamado com o cliente HTTP e a string de pesquisa, que faz uma requisição para a API Place do Google e retorna uma matriz de &lt;code&gt;PlaceIds&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Depois, a função cria um slice para armazenar as respostas de &lt;code&gt;PlaceDetail&lt;/code&gt; vindas da API do Google Places. &lt;/p&gt;

&lt;p&gt;A função inicia uma gorotina para cada &lt;code&gt;PlaceID&lt;/code&gt; obtido na resposta da &lt;code&gt;searchPlace&lt;/code&gt;, e estas gorotinas fazem chamadas à função &lt;code&gt;getPlaceDetail&lt;/code&gt; para obter detalhes para cada &lt;code&gt;PlaceID&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;O sincronismo dessas gorotinas é controlado utilizando um &lt;code&gt;WaitGroup&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ao terminar as chamadas à função &lt;code&gt;getPlaceDetail&lt;/code&gt;, a função &lt;code&gt;searchHandler&lt;/code&gt; configura o cabeçalho &lt;code&gt;"Content-Type"&lt;/code&gt; do response como &lt;code&gt;"application/json"&lt;/code&gt; e codifica o slice de &lt;code&gt;PlaceDetails&lt;/code&gt; em JSON para enviar como resposta ao cliente.&lt;/p&gt;

&lt;p&gt;Se algum erro ocorrer ao longo desses passos, a função irá retornar um status de erro HTTP 500 para o cliente junto com o erro que ocorreu.&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="c"&gt;// Esta função é chamada quando o endpoint /search é acessado.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;searchHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&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;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&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;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Criar um cliente HTTP com um tempo limite de 10 segundos.&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&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;Client&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Timeout&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Extrair a string de pesquisa a partir da query do request HTTP.&lt;/span&gt;
    &lt;span class="n"&gt;searchStr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;()&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;"query"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Faz uma chamada à API do Google Places para procurar por um lugar.&lt;/span&gt;
    &lt;span class="n"&gt;placeSearch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;searchPlace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;searchStr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Se houver um erro, retorna um status 500 e o erro.&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;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&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;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Cria um slice para armazenar os detalhes dos lugares.&lt;/span&gt;
    &lt;span class="n"&gt;totalPlaces&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;placeSearch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;details&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;PlaceDetail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;totalPlaces&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Inicializando um WaitGroup para sincronizar as goroutines&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;

    &lt;span class="c"&gt;// Faz uma chamada para obter detalhes de cada lugar baseado em PlaceID&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;placeSearch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Results&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;placeId&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c"&gt;// Chamando a função para obter os detalhes do local&lt;/span&gt;
            &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getPlaceDetail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;placeId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&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;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;
        &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PlaceId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Esperando todas as goroutines terminarem&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Configurar o cabeçalho HTTP 'Content-Type' para 'application/json'&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Codificar a resposta em JSON&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&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;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&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;h3&gt;
  
  
  Structs
&lt;/h3&gt;

&lt;p&gt;Para sustentar tudo isso e também para eu conseguir tratar o JSON recebido, eu criei quatro structs.&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;type&lt;/span&gt; &lt;span class="n"&gt;PlaceSearch&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Results&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;PlaceId&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"place_id"`&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="s"&gt;`json:"results"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;OpeningHours&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;OpenNow&lt;/span&gt;     &lt;span class="kt"&gt;bool&lt;/span&gt;     &lt;span class="s"&gt;`json:"open_now"`&lt;/span&gt;
    &lt;span class="n"&gt;WeekdayText&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"weekday_text"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Review&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;AuthorName&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"author_name"`&lt;/span&gt;
    &lt;span class="n"&gt;Text&lt;/span&gt;       &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"text"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;PlaceDetail&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Result&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt;                 &lt;span class="kt"&gt;string&lt;/span&gt;        &lt;span class="s"&gt;`json:"name"`&lt;/span&gt;
        &lt;span class="n"&gt;FormattedAddress&lt;/span&gt;     &lt;span class="kt"&gt;string&lt;/span&gt;        &lt;span class="s"&gt;`json:"formatted_address"`&lt;/span&gt;
        &lt;span class="n"&gt;FormattedPhoneNumber&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;        &lt;span class="s"&gt;`json:"formatted_phone_number"`&lt;/span&gt;
        &lt;span class="n"&gt;Website&lt;/span&gt;              &lt;span class="kt"&gt;string&lt;/span&gt;        &lt;span class="s"&gt;`json:"website"`&lt;/span&gt;
        &lt;span class="n"&gt;Rating&lt;/span&gt;               &lt;span class="kt"&gt;float64&lt;/span&gt;       &lt;span class="s"&gt;`json:"rating"`&lt;/span&gt;
        &lt;span class="n"&gt;BusinessStatus&lt;/span&gt;       &lt;span class="kt"&gt;string&lt;/span&gt;        &lt;span class="s"&gt;`json:"business_status"`&lt;/span&gt;
        &lt;span class="n"&gt;OpeningHours&lt;/span&gt;         &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;OpeningHours&lt;/span&gt; &lt;span class="s"&gt;`json:"opening_hours"`&lt;/span&gt;
        &lt;span class="n"&gt;Reviews&lt;/span&gt;              &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Review&lt;/span&gt;      &lt;span class="s"&gt;`json:"reviews"`&lt;/span&gt;
        &lt;span class="n"&gt;Url&lt;/span&gt;                  &lt;span class="kt"&gt;string&lt;/span&gt;        &lt;span class="s"&gt;`json:"url"`&lt;/span&gt;
        &lt;span class="n"&gt;PriceLevel&lt;/span&gt;           &lt;span class="kt"&gt;int&lt;/span&gt;           &lt;span class="s"&gt;`json:"price_level"`&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="s"&gt;`json:"result"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Main
&lt;/h3&gt;

&lt;p&gt;A minha função main, responsável por iniciar o meu software, acabou ficando assim:&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;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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GCP_TOKEN_PLACE_API"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Erro ao carregar o arquivo .env"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;gcpToken&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Insira o Token GCP_TOKEN_PLACE_API na variável de ambiente"&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;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/search"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;searchHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&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;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CORS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AllowedOrigins&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&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;DefaultServeMux&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;Essa função basicamente verifica se o token de autenticação está inserido na variável de ambiente. (Em alguns momentos eu usei a variável de ambiente setada no meu OS, em outros momentos usei &lt;code&gt;.env&lt;/code&gt; e em outros o token estava exposto no código-fonte mesmo.)&lt;/p&gt;

&lt;h4&gt;
  
  
  A rotina do http server
&lt;/h4&gt;

&lt;p&gt;O servidor é iniciado na porta 8080 e eu passo um handler que faz a mão de aceitar a requisição vindo de outra origem. Eu separei a aplicação em duas imagens Docker onde o backend roda na porta 8080 e o frontend roda na porta 80.&lt;/p&gt;

&lt;p&gt;Enquanto eu fazia a aplicação, eu tive problemas de CORS quando tentava fazer a requisição a partir do meu frontend. A requisição feita diretamente pela porta 8080 acontecia normalmente, enquanto o navegador encontrava problemas com isso.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O mecânismo CORS suporta requisições seguras do tipo cross-origin e transferências de dados entre navegadores e servidores web.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Esse servidor ainda usa uma &lt;em&gt;handle function&lt;/em&gt; que faz a gestão das rotas. No caso eu criei uma rota &lt;code&gt;/search&lt;/code&gt; onde a partir dela eu chamo outra função que é a responsável por continuar a requisição e posteriormente isso vai me retornar um JSON.&lt;/p&gt;

&lt;p&gt;Parte 2: &lt;strong&gt;Frontend&lt;/strong&gt;&lt;br&gt;
O frontend foi feito com HTML, CSS, JavaScript, Bootstrap e o bom e velho jQuery. &lt;/p&gt;

&lt;p&gt;Como eu queria testar alguns filtros no front, eu implementei o &lt;a href="https://datatables.net/" rel="noopener noreferrer"&gt;Datatables&lt;/a&gt;, um recurso que eu já conhecia de outros carnavais e que sempre me ajudou na hora de criar tabelas dinâmicas no frontend e ele tem como dependência o jQuery.&lt;/p&gt;

&lt;p&gt;Eu poderia entrar a fundo nos conceitos de frontend e ficar explicando o motivo de eu não ter usado React, Vue ou qualquer outro super poder de frontend, porém, como eu falei, o desafio era primeiro implementar e fazer funcionar e depois, quem sabe, um dia, eu refaça o frontend usando alguma biblioteca do momento.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5je8fbhposkyjrbk15ww.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5je8fbhposkyjrbk15ww.png" alt="Image Print do Frontend da aplicação" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aqui você encontra uma base do HTML usado no projeto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"pt-br"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;AquiPertin - Encontre tudo o que você precisa, onde você precisa.&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Bootstrap --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;crossorigin=&lt;/span&gt;&lt;span class="s"&gt;"anonymous"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"&lt;/span&gt;
          &lt;span class="na"&gt;integrity=&lt;/span&gt;&lt;span class="s"&gt;"sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Datatables --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.datatables.net/1.10.25/css/dataTables.bootstrap4.min.css"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="nf"&gt;#contentResultTable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"content vh-100"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;header&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar navbar-light pt-5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar-brand"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Aqui&lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;Pertin&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar-text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;_simples assim :)&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar-text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Encontre tudo o que você precisa.&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row align-items-center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mx-auto"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-justify font-weight-bold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mt-5"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"myForm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-group"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"query"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-control"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"query"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"query"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Ex: Restaurantes próximos"&lt;/span&gt;
                                   &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-primary mt-3"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Consultar&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

                        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-group"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"onlyOpen"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"onlyOpen"&lt;/span&gt; &lt;span class="na"&gt;checked&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"onlyOpen"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mt-3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Mostrar somente lugares abertos agora&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

                    &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;aria-hidden=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal fade"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"reviewsModal"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"dialog"&lt;/span&gt; &lt;span class="na"&gt;tabindex=&lt;/span&gt;&lt;span class="s"&gt;"-1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal-dialog reviews-modal-dialog"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal-content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal-header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;h5&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal-title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Avaliações&lt;span class="nt"&gt;&amp;lt;/h5&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"close"&lt;/span&gt; &lt;span class="na"&gt;data-dismiss=&lt;/span&gt;&lt;span class="s"&gt;"modal"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"closeModals()"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;times;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal-body"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"reviewsContent"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal-footer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-secondary"&lt;/span&gt; &lt;span class="na"&gt;data-dismiss=&lt;/span&gt;&lt;span class="s"&gt;"modal"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"closeModals()"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Fechar&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Modal --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;aria-hidden=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;aria-labelledby=&lt;/span&gt;&lt;span class="s"&gt;"hoursModalLabel"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal fade"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"hoursModal"&lt;/span&gt; &lt;span class="na"&gt;tabindex=&lt;/span&gt;&lt;span class="s"&gt;"-1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal-dialog"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal-content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal-header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;h5&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal-title"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"hoursModalLabel"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Horários de Funcionamento&lt;span class="nt"&gt;&amp;lt;/h5&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"close"&lt;/span&gt; &lt;span class="na"&gt;data-dismiss=&lt;/span&gt;&lt;span class="s"&gt;"modal"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"closeModals()"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;times;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal-body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="c"&gt;&amp;lt;!-- O conteúdo do horário de funcionamento será inserido aqui pelo JavaScript --&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal-footer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-secondary"&lt;/span&gt; &lt;span class="na"&gt;data-dismiss=&lt;/span&gt;&lt;span class="s"&gt;"modal"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"closeModals()"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Fechar&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container-fluid mt-4"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"contentResultTable"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display: none;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-md-12"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;table&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"table table-striped table-bordered mt-5"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"resultTable"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;thead&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Nome da empresa"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Nome&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Endereço da empresa"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Endereço&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Localização no Google Maps"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Mapa&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Número de telefone da empresa"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Telefone&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Avaliações do usuário"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Avaliações&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Website da empresa"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Site&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Classificação média dos usuários"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Nota&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"Horário de funcionamento da empresa"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Funcionamento&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/thead&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;
                    &lt;span class="c"&gt;&amp;lt;!-- As linhas com os dados da requisição serão adicionadas aqui pelo JavaScript --&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- jQuery --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Datatables JS --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.datatables.net/1.10.25/js/jquery.dataTables.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.datatables.net/1.10.25/js/dataTables.bootstrap4.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Bootstrap JS Bundle --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- App JS --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"search.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Abaixo eu compartilho com você um JS onde eu me dei ao trabalho de comentar quase que linha a linha para explicar o que eu fiz.&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="c1"&gt;// armazena os dados recuperados&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;table&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;dataStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="c1"&gt;// este código é executado quando o documento HTML é completamente carregado&lt;/span&gt;
&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// inicia o plugin DataTables na tabela #resultTable&lt;/span&gt;
    &lt;span class="nx"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;#resultTable&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nc"&gt;DataTable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="c1"&gt;// configura a linguagem em português para o DataTable&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;language&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="s2"&gt;url&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;https://cdn.datatables.net/plug-ins/1.10.24/i18n/Portuguese-Brasil.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="c1"&gt;// recupera uma instância DataTable existente, se aplicável&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;retrieve&lt;/span&gt;&lt;span class="dl"&gt;"&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="c1"&gt;// destrói qualquer instância DataTable existente para inicializar uma nova&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;destroy&lt;/span&gt;&lt;span class="dl"&gt;"&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="c1"&gt;// ativa tooltips para quaisquer elementos com um atributo de título&lt;/span&gt;
    &lt;span class="nf"&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;[title]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;tooltip&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// gera o conteúdo HTML a ser adicionado ao modal de revisão&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateModalContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reviewData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;reviewData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;review&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;review&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rating&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;rating&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&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;fullStars&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;i class="fas fa-star"&amp;gt;&amp;lt;/i&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rating&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;halfStar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;rating&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;0&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;&amp;lt;i class="fas fa-star-half-alt"&amp;gt;&amp;lt;/i&amp;gt;&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="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;h5&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;fullStars&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;halfStar&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/h5&amp;gt;
                    &amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/p&amp;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;join&lt;/span&gt;&lt;span class="p"&gt;(&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="c1"&gt;// abre um modal, o conteúdo é gerado dependendo do parâmetro 'type'&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;openModal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&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;modalContent&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;modal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reviews&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nx"&gt;modalContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generateModalContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dataStore&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reviews&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;modal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;#reviewsModal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hours&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nx"&gt;modalContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dataStore&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;opening_hours&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;weekday_text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/p&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;modal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;#hoursModal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.modal-body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;modalContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;show&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="c1"&gt;// fecha todos os modals abertos&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;closeModals&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&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;#reviewsModal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hide&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&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;#hoursModal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hide&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="c1"&gt;// gera o conteúdo HTML para resultados de busca&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createResultHtml&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="c1"&gt;// filtra os resultados de acordo com a opção "Apenas abertos"&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;onlyOpen&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;opening_hours&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;opening_hours&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;open_now&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// ordena os resultados de acordo com a opção "Ordenar por"&lt;/span&gt;
    &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&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="c1"&gt;// se a opção for "Avaliações", ordena por avaliações&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;a_open&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;opening_hours&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;opening_hours&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;open_now&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&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;b_open&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;opening_hours&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;opening_hours&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;open_now&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// se a opção for "Apenas abertos", ordena por abertos&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a_open&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;b_open&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;a_open&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;b_open&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// a_open false, b_open true, move a down&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// se a opção for "Avaliações", ordena por avaliações - a ser implementado&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;a_rating&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rating&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&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;b_rating&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rating&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;b_rating&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;a_rating&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// armazena os dados para uso posterior&lt;/span&gt;
    &lt;span class="nx"&gt;dataStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// gera o HTML para cada resultado&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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="c1"&gt;// se o local não tiver avaliações, o valor padrão é 0&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rating&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rating&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rating&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// gera o HTML para as estrelas de avaliação&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fullStars&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;i class="fas fa-star"&amp;gt;&amp;lt;/i&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;halfStar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;rating&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;0&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;&amp;lt;i class="fas fa-star-half-alt"&amp;gt;&amp;lt;/i&amp;gt;&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="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ratingHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;fullStars&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;halfStar&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// gera os detalhes do local&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;details&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// se o valor for indefinido, o valor padrão é "Not Available"&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Not Available&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;formatted_address&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Not Available&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;phoneNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;formatted_phone_number&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Not Available&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;reviews&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reviews&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reviews&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reviews&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;website&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;website&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Not Available&lt;/span&gt;&lt;span class="dl"&gt;"&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="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Not Available&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ratingHTML&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="c1"&gt;// se o local estiver aberto, o valor padrão é "Open", caso contrário, "Closed"&lt;/span&gt;
            &lt;span class="na"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;opening_hours&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;opening_hours&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;open_now&lt;/span&gt;
                &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;span class='badge bg-success'&amp;gt;&amp;lt;i class='fas fa-arrow-up'&amp;gt;&amp;lt;/i&amp;gt; Open&amp;lt;/span&amp;gt;&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;&amp;lt;span class='badge bg-danger'&amp;gt;&amp;lt;i class='fas fa-arrow-down'&amp;gt;&amp;lt;/i&amp;gt; Closed&amp;lt;/span&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="c1"&gt;// retorna a linha da tabela HTML&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getTableRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// une todas as linhas em uma única string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// gera uma linha de tabela HTML a partir de detalhes de um local&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getTableRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// retorna a linha da tabela HTML usando template literals&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`
      &amp;lt;tr&amp;gt;
            &amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;&amp;lt;a href="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" target="_blank"&amp;gt;Ver link&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;&amp;lt;a href="tel:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;phoneNumber&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;phoneNumber&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;&amp;lt;a href="#" onclick="openModal(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, 'reviews')"&amp;gt;Ver avaliações (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reviews&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;&amp;lt;a href="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;website&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" target="_blank"&amp;gt;Acessar site&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;&amp;lt;a href="#" onclick="openModal(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, 'hours')"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/a&amp;gt;&amp;lt;/td&amp;gt;
      &amp;lt;/tr&amp;gt;
   `&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt;
&lt;span class="c1"&gt;// adiciona um listener de evento para o formulário de pesquisa&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;myForm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// recupera o valor do campo de entrada - principal valor de pesquisa do App&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;query&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contentResultTable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;block&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// destrói a tabela existente antes de atualizar os dados usando o plugin DataTables&lt;/span&gt;
    &lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// primeiro destruir a tabela&lt;/span&gt;
    &lt;span class="c1"&gt;// faz uma solicitação (promise) para o servidor backend usando o valor de pesquisa&lt;/span&gt;
    &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`http://localhost:8080/search?query=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&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;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="c1"&gt;// converte a resposta em JSON&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="c1"&gt;// atualiza a tabela com os dados recuperados&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;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// atualiza o conteúdo da tabela com os dados recuperados&lt;/span&gt;
            &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resultTable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tbody&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createResultHtml&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="c1"&gt;// inicia o plugin DataTables na tabela #resultTable&lt;/span&gt;
            &lt;span class="nx"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;#resultTable&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nc"&gt;DataTable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;language&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="s2"&gt;url&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;https://cdn.datatables.net/plug-ins/1.10.24/i18n/Portuguese-Brasil.json&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;retrieve&lt;/span&gt;&lt;span class="dl"&gt;"&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="p"&gt;})&lt;/span&gt;
        &lt;span class="c1"&gt;// captura quaisquer erros e os imprime no console&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error:&lt;/span&gt;&lt;span class="dl"&gt;'&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;span class="c1"&gt;// adiciona um listener de evento para o botão "Limpar"&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;placeholders&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="s2"&gt;Ex: Restaurante na Paulista&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;Ex: Mecânica em Curitiba &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;Ex: Café no aeroporto de Guarulhos&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;Ex: Cinema em Porto Alegre&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;Ex: Ponto de táxi em Copacabana&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;Ex: Rodoviária em Fortaleza&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;Ex: Museus em BH&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;Ex: Farmácias no centro&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;Ex: Supermercados próximos&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;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// altera o placeholder do campo de entrada a cada 2 segundos&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;alterarPlaceholder&lt;/span&gt;&lt;span class="p"&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;inputElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;query&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;inputElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;placeholder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;placeholders&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;placeholders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&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="c1"&gt;// adiciona um listener de evento para o "onload" do objeto window&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;alterarPlaceholder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2000&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;h3&gt;
  
  
  Anatomia da aplicação
&lt;/h3&gt;

&lt;p&gt;Esta aplicação web é uma combinação de HTML, CSS, JavaScript e usa uma API Rest em Go para buscar lugares próximos baseado na consulta do usuário.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTML&lt;/strong&gt;: O código HTML estrutura o layout do site com elementos de entrada de usuário, um formulário para enviar query, um checkbox para mostrar apenas lugares abertos agora, botões de ação, etc. &lt;/p&gt;

&lt;p&gt;Ele também inclui área onde os resultados da API da busca serão mostrados em uma tabela. &lt;/p&gt;

&lt;p&gt;Além disso, são incluídos os modais (janelas de diálogos) para exibir as avaliações e os horários de funcionamento dos lugares.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSS&lt;/strong&gt;: Os estilos CSS foram incluídos para melhorar a aparência do site. Nesse caso, é usada principalmente para ajustar a largura da tabela de resultados e para estilizar a tabela. O restante são classes do Bootstrap que já organizam todo o layout.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JavaScript&lt;/strong&gt;: É usado para manipular as interações e ações do usuário, enviar solicitações à API, receber respostas e manipulá-las e atualizar a interface do usuário de acordo.&lt;/p&gt;

&lt;p&gt;Especificamente, o código JavaScript faz o seguinte:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inicia criando a tabela de resultados com DataTable, uma biblioteca JQuery que adiciona funcionalidades de interação à tabelas em HTML.&lt;/li&gt;
&lt;li&gt;Define uma função generateModalContent que cria o conteúdo HTML a ser exibido nos modais de avaliações.&lt;/li&gt;
&lt;li&gt;Define funções openModal e closeModals para controlar a exibição dos modais de avaliações e horários de funcionamento.&lt;/li&gt;
&lt;li&gt;Define a função createResultHtml para criar as linhas da tabela de resultados. Esta função recebe os dados da API, filtra se o usuário marcou para ver só locais abertos agora, organiza os locais considerando se está aberto e a nota de avaliação do local.&lt;/li&gt;
&lt;li&gt;A função getTableRow retorna um template string que é a linha da tabela de resultados.&lt;/li&gt;
&lt;li&gt;Adiciona um listener de evento "submit" ao formulário. Quando o formulário é submetido, a consulta de entrada do usuário é capturada e uma solicitação é enviada à API. Quando a resposta é recebida da API, a tabela é preenchida com os dados da resposta.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por fim, a função &lt;code&gt;alterarPlaceholder&lt;/code&gt; &lt;em&gt;(que nome tosco)&lt;/em&gt; altera o placeholder do input de consulta a cada 2 segundos, dando exemplos ao usuário de como usar a aplicação.&lt;/p&gt;

&lt;p&gt;O código JavaScript está usando o AJAX (com a função fetch) para realizar requisições HTTP assíncronas à API do servidor, e então, usa os dados recebidos para atualizar dinamicamente a interface de usuário. &lt;/p&gt;




&lt;p&gt;Em resumo, neste App as consultas são feitas à API REST desenvolvida em Go (backend) e os resultados são processados e apresentados na forma de uma tabela no navegador do usuário (frontend).&lt;/p&gt;

&lt;p&gt;Este App é um exemplo simples de como uma API Restful pode ser utilizada para buscar e exibir dados dinamicamente no frontend de uma aplicação web.&lt;/p&gt;




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

&lt;p&gt;O desafio do projeto foi concluído com sucesso.&lt;/p&gt;

&lt;p&gt;Se você chegou até aqui, muito provavelmente você percebeu que o App poderia ter sido feito seguindo uma série de boas práticas no desenvolvimento de software.&lt;/p&gt;

&lt;p&gt;A minha justificativa para isso é que este era um ambiente de testes construído para errar, ou seja, o meu objetivo era cometer erros durante o processo e me colocar em situações onde eu precisaria buscar uma solução para um problema que não tinha sido previsto anteriormente.&lt;/p&gt;

&lt;p&gt;Se este App fosse aproveitado para algo realmente em produção, muita coisa precisaria ser feita, como começar escrevendo todas as funções a partir de testes, aplicar os conceitos de arquitetura e código limpos, organizar o projeto de forma física e lógica aplicando boas práticas de desenvolvimento.&lt;/p&gt;

&lt;p&gt;Apenas a critério de conhecimento, eu comecei a escrever a requisição HTTP só para testar o endpoint e quando eu vi tinham se passado 6 horas!&lt;/p&gt;

&lt;p&gt;Eu cometi erros como por exemplo não ir fazendo commits, ou pior ainda, nem tinha criado um repositório Git e já tinha horas de código.&lt;/p&gt;

&lt;p&gt;Outro erro de noob foi iniciar o repo com sono e cansado e acabar expondo o token da API na variável de ambiente e commitar isso!&lt;/p&gt;

&lt;p&gt;Outro erro ainda mais tosco foi eu não ter feito um mock do payload do Google para implementar o frontend. Eu fiquei testando em produção, fazendo requisições na API do Google a cada teste que eu fazia 😂&lt;/p&gt;

&lt;p&gt;O Google cobra por SKU, ou seja, a cada informação que eu busco eles me cobram. E tem informações que custam mais caro do que outras, e algumas ainda existem uma cobrança à parte quando o consumo fica dentro de um determinado range.&lt;/p&gt;

&lt;p&gt;O resultado dessa brincadeira consumindo dados de uma API em produção foi de R$ 726,29. Obviamente que eu usei um voucher do Google Cloud para testar a aplicação e não precisei pagar nenhum real por isso.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frckpowi59ce6l6ef6xq9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frckpowi59ce6l6ef6xq9.png" alt="Image Custo do GCP" width="800" height="216"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Eu ainda tive que lidar com HTML e CSS que há muitos anos eu não colocava a mão de verdade. Javascript eu ainda sabia como fazer algumas coisas e onde procurar ajuda quando precisasse. &lt;/p&gt;

&lt;p&gt;Eu também tive que estudar sobre Docker, CORS, requisições http a partir do resultado de uma outra requisição http, etc, etc.&lt;/p&gt;

&lt;p&gt;No fim das contas eu considero que o resultado foi duca e certamente eu vou criar mais implementações assim, sempre testando serviços reais que podem ser usados em aplicações reais.&lt;/p&gt;

&lt;p&gt;Se você gostou deste artigo, considere deixar um comentário. Eu vou ficar feliz em saber a tua opinião sobre tudo isso.&lt;/p&gt;

&lt;p&gt;Até a próxima.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>PoC: Evoluindo o Busca Cep com DDD e clean code</title>
      <dc:creator>Marcelo Matz</dc:creator>
      <pubDate>Fri, 01 Sep 2023 16:13:53 +0000</pubDate>
      <link>https://dev.to/matzcoelho/poc-evoluindo-o-busca-cep-com-ddd-e-clean-code-389</link>
      <guid>https://dev.to/matzcoelho/poc-evoluindo-o-busca-cep-com-ddd-e-clean-code-389</guid>
      <description>&lt;p&gt;Este post é uma continuação do post anterior. Dessa vez eu vou falar sobre as melhorias que eu fiz no código e na evolução do script do Busca Cep que agora virou até mesmo uma Prova de Conceito - PoC.&lt;/p&gt;

&lt;p&gt;Pesquisando na internet sobre a definição de prova de conceito, eu encontrei isso aqui:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Uma prova de conceito (PoC) é uma demonstração prática da viabilidade de uma ideia ou método. É uma implementação resumida, simples e incompleta, que antecede o protótipo do projeto.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Dessa vez eu apliquei um pouco de domain-driven design, clean code, testes e fiz até mesmo um front-end vergonhoso e cheio de Javascript e CSS feitos de forma bem artesanal e &lt;em&gt;o que você vai ler abaixo é a minha implementação resumida, simples e incompleta do Busca Cep.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Aqui está o &lt;a href="https://github.com/marcelomatz/buscaCep" rel="noopener noreferrer"&gt;link para o repositório do projeto no GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Criando um Serviço de Busca de CEP Simples com Go&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O Busca Cep nasceu junto com &lt;a href="https://dev.to/marcelomatz/criando-um-servico-de-busca-de-cep-simples-com-go-1ocj"&gt;este artigo&lt;/a&gt; que fala do meu aprendizado em cima da linguagem de programação Go. &lt;/p&gt;

&lt;p&gt;Eu demonstrei como fazer uma implementação usando &lt;em&gt;Go&lt;/em&gt; extremamente simples para consultar, consumir e tratar as informações recebidas a partir de uma requisição http para o web service da &lt;a href="https://viacep.com.br/" rel="noopener noreferrer"&gt;ViaCep&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Busca Cep PoC
&lt;/h2&gt;

&lt;p&gt;Como &lt;strong&gt;o meu objetivo&lt;/strong&gt; é estudar sobre desenvolvimento de software, eu implementei algumas melhorias em cima do exemplo do Busca Cep (criado no artigo anterior) e aproveitei essa implementação para colocar em prática alguns conceitos que são fundamentais no dia a dia de um dev.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vamos falar de commit
&lt;/h3&gt;

&lt;p&gt;O &lt;a href="https://github.com/marcelomatz/buscaCep/commit/bddc55196b416316f8c1ad867d2677b480632d79" rel="noopener noreferrer"&gt;primeiro commit&lt;/a&gt; que eu fiz foi implementando um tratamento de erros, ainda na função Main.&lt;/p&gt;

&lt;p&gt;Na real, na real, foi nesse momento que eu pensei em transformar tudo isso em uma prova de conceito e assim começou a pequena jornada de mudanças.&lt;/p&gt;

&lt;p&gt;Mais adiante ainda eu viria a começar a separar o software de acordo com as responsabilidades de cada coisa, mas neste momento eu lembro de estar focado lendo sobre erros no Go.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffn4mnfynh5gqyt8w16ic.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffn4mnfynh5gqyt8w16ic.png" alt="Image Improve error handling &amp;amp; reporting in Main.go" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O mais interessante de tudo, na minha opinião, é que muitas vezes por causa de uma simples mudança no código, a maneira como nós pensamos muda completamente.&lt;/p&gt;

&lt;p&gt;Meio que faz sentido aquilo que o &lt;em&gt;mano Alberto falou: "A mente que se abre a uma nova ideia jamais voltará ao seu tamanho original"&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Aprendizados
&lt;/h3&gt;

&lt;p&gt;O meu maior aprendizado com essa PoC foi perceber que as alterações mais sutis, foram as que mais me fizeram pensar e consequentemente isso me fez escrever menos código.&lt;/p&gt;

&lt;p&gt;Como diz o filósofo:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Pensar melhor e executar melhor é melhor do que pensar pior e executar pior.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As startups gostam de adotar o discurso de: &lt;em&gt;erre rápido, corrija rápido!&lt;/em&gt;&lt;br&gt;
&lt;em&gt;A moral é que até hoje eles estão errando rápido e levando semanas para corrigir&lt;/em&gt; 😂&lt;/p&gt;

&lt;p&gt;Sobre o commit do tratamento de erros:&lt;br&gt;
&lt;code&gt;incluí um novo método isEmpty na struct ViaCep para verificar se todas as suas propriedades estão vazias. Isso ajuda a lidar com situações em que a pesquisa CEP não retorna nenhum resultado. Consequentemente, uma resposta de erro com a mensagem "CEP não encontrado" é retornada quando um resultado de pesquisa CEP está vazio. Essa alteração aprimora o tratamento de erros e leva a um status de resposta HTTP mais preciso.&lt;/code&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  DDD - Primeiros passos com Domain-Driven Design.
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Domain-Driven Design (DDD)&lt;/strong&gt; é uma abordagem de design de software que coloca o domínio do problema no centro do processo de desenvolvimento.&lt;/p&gt;

&lt;p&gt;Desde que eu comecei a ler o livro do Eric Evans sobre DDD, além de me sentir um pouco mais burro, eu fui entendendo como e quando faz sentido criar essa separação em camadas.&lt;/p&gt;

&lt;p&gt;E justamente por eu entender isso é que eu sei que uma PoC como o Busca Cep não tem a necessidade de se trabalhar um design de software mais avançado. Tanto é verdade que a primeira versão não passava de um simples script na Main.&lt;/p&gt;

&lt;p&gt;Eu ignorei este fato de ser um projeto pequeno e defini que a ViaCep é o meu domínio principal. O meu código todo gira em torno de fazer uma requisição http no ViaCep.&lt;/p&gt;

&lt;p&gt;A partir disso eu parti para organizar o meu projeto de forma que essa organização reflita essa separação entre as minhas regras de negócio e o domínio principal.&lt;/p&gt;

&lt;p&gt;O &lt;a href="https://github.com/marcelomatz/buscaCep/commit/78a2fc92aaf607a7a3e5755499c509c1c2cb51a4" rel="noopener noreferrer"&gt;commit&lt;/a&gt; chama-se: &lt;strong&gt;Refactoring ViaCep data lookup to improve modularity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Este commit reorganiza o código BuscaCep em pacotes diferentes. O principal objetivo era melhorar a modularidade do código, separando responsabilidades e tornando o código mais fácil de testar.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;A estrutura ViaCep e a função BuscaCep foram movidas de main.go para um novo arquivo, domain/viacep.go. Este arquivo agora encapsula funcionalidades relacionadas à busca e verificação de dados do ViaCep.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Da mesma forma, a função BuscaCepHandle foi movida para um novo arquivo, handlers/cep.go. Este arquivo agora trata do fluxo de solicitação/resposta HTTP para pesquisas CEP (Código Postal).&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Dois novos arquivos de teste domain/viacep_test.go e handlers/cep_test.go também foram criados, estabelecendo as bases para futuros casos de teste.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;O que eu fiz de mudança no Busca Cep neste momento foi separar o projeto de forma física e lógica. Eu criei um diretório chamado &lt;code&gt;domain&lt;/code&gt; e outro chamado &lt;code&gt;handlers&lt;/code&gt; e separei os arquivos Go correspondentes dentro de cada diretório.&lt;/p&gt;

&lt;p&gt;Em &lt;strong&gt;domain&lt;/strong&gt; eu separei justamente o que está relacionado ao domínio do meu negócio, que neste caso é o web service do ViaCep onde eu faço a requisição http. Em &lt;strong&gt;handlers&lt;/strong&gt; eu deixei as funções que tratam de requests, parâmetros, etc.&lt;/p&gt;

&lt;p&gt;Por mais que existam formas mais elegantes de se fazer essa separação, pra mim o aprendizado que eu tive por simplesmente ter parado um tempo para pensar nessa separação foi sensacional.&lt;/p&gt;

&lt;p&gt;Sem falar que isso tornou o meu código muito mais fácil de ser testado. Eu consigo pensar o que eu quero testar e consigo separar isso de uma forma mais organizada.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testes
&lt;/h3&gt;

&lt;p&gt;Enquanto eu avançava na implementação das melhorias, eu queria ter uma experiência trabalhando com testes em Go.&lt;/p&gt;

&lt;p&gt;Tanto para erros, quanto para testes, o Go oferece um suporte built-in maravilhoso. Quem já passou raiva com outros linguagens de programação por causa de captura de erros, sabe o luxo que é ter uma lang que realmente se preocupa com isso.&lt;/p&gt;

&lt;p&gt;Eu ainda vou estudar mais sobre testes e certamente vou escrever mais sobre este assunto. Por enquanto eu estou satisfeito com o que eu aprendi sobre testes em Go.&lt;/p&gt;

&lt;h3&gt;
  
  
  Refatorando
&lt;/h3&gt;

&lt;p&gt;Refatorar código é uma delícia. Sério! Eu sou do pensamento que todo dev deveria amar o processo de refatorar código.&lt;/p&gt;

&lt;p&gt;Parece que as coisas se tornam mais simples e ao mesmo tempo mais divertidas de serem feitas quando a gente refatora.&lt;/p&gt;

&lt;p&gt;Eu comecei a refatorar o projeto, criar as separações e ver que eu podia ir mais longe, resolvi simular um front-end.&lt;/p&gt;

&lt;p&gt;Criei uma tela que permite ao usuário fazer o input de um cep e ver as informações sobre ele.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8m9qfielfoie6bscbqex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8m9qfielfoie6bscbqex.png" alt="Image print do frontend" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O mais legal é que, para testar isso dentro dessa aplicação e não precisar subir o backend de um lado e o front de outro, eu fiz com que a rota principal ("/") retornasse um arquivo html, enquanto a outra rota faz a requisição para o web service.&lt;/p&gt;

&lt;p&gt;No fim das contas, no frontend eu fiz um tratamento usando Javascript para exibir as informações na tela, mas por baixo dos panos o backend em Go é quem faz todo o processo.&lt;/p&gt;

&lt;p&gt;Mais para frente, quem sabe, eu não faça um frontend (true) que consome o microsserviço do Busca Cep.&lt;/p&gt;

&lt;p&gt;Por enquanto eu to feliz com o que foi feito até aqui com algo que começou super simples e foi ganhando corpo e servindo ao seu propósito de ser algo de valor acadêmico.&lt;/p&gt;

&lt;p&gt;Considere deixar um comentário se você tem alguma dúvida, crítica ou sugestão.&lt;/p&gt;

&lt;p&gt;Até a próxima!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Criando um Serviço de Busca de CEP Simples com Go</title>
      <dc:creator>Marcelo Matz</dc:creator>
      <pubDate>Thu, 31 Aug 2023 13:33:38 +0000</pubDate>
      <link>https://dev.to/matzcoelho/criando-um-servico-de-busca-de-cep-simples-com-go-1ocj</link>
      <guid>https://dev.to/matzcoelho/criando-um-servico-de-busca-de-cep-simples-com-go-1ocj</guid>
      <description>&lt;p&gt;Neste artigo, faremos uma imersão em um serviço básico escrito em Go que pode servir para buscar informações de um CEP (Código de Endereçamento Postal) no Brasil. &lt;/p&gt;

&lt;p&gt;Vamos usar a &lt;a href="https://viacep.com.br/" rel="noopener noreferrer"&gt;API ViaCep&lt;/a&gt; para busca de CEPs brasileiros.&lt;/p&gt;

&lt;h3&gt;
  
  
  Estrutura do Código
&lt;/h3&gt;

&lt;p&gt;O código é dividido em três partes principais:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A definição do tipo ViaCep, que é uma estrutura (struct) que espelha os dados retornados pela API ViaCep.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A função main, que inicia um servidor HTTP e define o roteamento.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;As funções BuscaCepHandle e BuscaCep que lidam com a lógica principal da aplicação.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Definindo o tipo ViaCep
&lt;/h3&gt;

&lt;p&gt;Vamos definir o tipo ViaCep como uma estrutura com vários campos do tipo string. Esses campos refletem as propriedades do objeto JSON que recebemos da API ViaCep.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type ViaCep struct {
    Cep         string `json:"cep"`
    Logradouro  string `json:"logradouro"`
    Complemento string `json:"complemento"`
    Bairro      string `json:"bairro"`
    Localidade  string `json:"localidade"`
    Uf          string `json:"uf"`
    Ibge        string `json:"ibge"`
    Gia         string `json:"gia"`
    Ddd         string `json:"ddd"`
    Siafi       string `json:"siafi"`
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;As tags json:"..." anexadas a cada campo da struct fazem o rolê de instruir o pacote encoding/json sobre como fazer o mapeamento do JSON para a struct em Go.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Função Main
&lt;/h3&gt;

&lt;p&gt;Na função main começamos escutando na porta &lt;code&gt;8080&lt;/code&gt; e configuramos um roteamento de URL simples, onde todas as requisições para a rota &lt;code&gt;/&lt;/code&gt; são tratadas pela função &lt;code&gt;BuscaCepHandle&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;func main() {
    http.HandleFunc("/", BuscaCepHandle)
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
    return
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se um erro ocorrer durante &lt;code&gt;http.ListenAndServe&lt;/code&gt;, nós simplesmente retornamos e encerramos a execução do programa.&lt;/p&gt;

&lt;h3&gt;
  
  
  Funções BuscaCepHandle e BuscaCep
&lt;/h3&gt;

&lt;p&gt;A função &lt;code&gt;BuscaCepHandle&lt;/code&gt; é nossa manipuladora de requisições HTTP. Ela lida com todas as solicitações que chegam à raíz ("/") da nossa aplicação.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func BuscaCepHandle(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path != "/" {
        w.WriteHeader(http.StatusNotFound)
        return
    }
    cepParam := r.URL.Query().Get("cep")
    if cepParam == "" || len(cepParam) != 8 {
        w.WriteHeader(http.StatusBadRequest)
        return
    }
    // ... (código truncado por brevidade)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta função verifica se o &lt;strong&gt;parâmetro do cep&lt;/strong&gt; foi passado na requisição e se ele possui 8 caracteres. Se o CEP não for válido, devolvemos um status HTTP 400.&lt;/p&gt;

&lt;p&gt;A função &lt;code&gt;BuscaCep&lt;/code&gt; é uma função auxiliar usada por &lt;code&gt;BuscaCepHandle&lt;/code&gt; para fazer a solicitação real para a API ViaCep e processar os dados de resposta.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func BuscaCep(cep string) (*ViaCep, error) {
    url := "https://viacep.com.br/ws/" + cep + "/json/"
    resp, err := http.Get(url)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()
    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }
    var viaCep ViaCep
    err = json.Unmarshal(body, &amp;amp;viaCep)
    if err != nil {
        return nil, err
    }
    return &amp;amp;viaCep, nil
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta função faz uma requisição para a API ViaCep, lê a resposta e a deserializa em um objeto ViaCep. &lt;/p&gt;

&lt;p&gt;A função retorna um ponteiro para um objeto ViaCep ou um erro, caso algo dê errado durante a solicitação HTTP ou a deserialização do JSON da resposta.&lt;/p&gt;

&lt;p&gt;Abaixo eu deixo um exemplo do código completo para você analisar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "encoding/json"
    "io"
    "net/http"
)

type ViaCep struct {
    Cep         string `json:"cep"`
    Logradouro  string `json:"logradouro"`
    Complemento string `json:"complemento"`
    Bairro      string `json:"bairro"`
    Localidade  string `json:"localidade"`
    Uf          string `json:"uf"`
    Ibge        string `json:"ibge"`
    Gia         string `json:"gia"`
    Ddd         string `json:"ddd"`
    Siafi       string `json:"siafi"`
}

func main() {
    http.HandleFunc("/", BuscaCepHandle)
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        return
    }
}

func BuscaCepHandle(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path != "/" {
        w.WriteHeader(http.StatusNotFound)
        return
    }
    cepParam := r.URL.Query().Get("cep")
    if cepParam == "" || len(cepParam) != 8 {
        w.WriteHeader(http.StatusBadRequest)
        return
    }
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusOK)
    viaCep, err := BuscaCep(cepParam)
    if err != nil {
        w.WriteHeader(http.StatusInternalServerError)
        return
    }
    err = json.NewEncoder(w).Encode(viaCep)
    if err != nil {
        return
    }

}

func BuscaCep(cep string) (*ViaCep, error) {
    url := "https://viacep.com.br/ws/" + cep + "/json/"
    resp, err := http.Get(url)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()
    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }
    var viaCep ViaCep
    err = json.Unmarshal(body, &amp;amp;viaCep)
    if err != nil {
        return nil, err
    }
    return &amp;amp;viaCep, nil
}

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

&lt;/div&gt;






&lt;p&gt;Pronto! &lt;br&gt;
Isso é o suficiente para criar um microsserviço simples de busca de CEP usando Go.&lt;/p&gt;

&lt;p&gt;Se você quiser ter acesso ao código completo, pode acessar o &lt;a href="https://github.com/marcelomatz/buscaCep" rel="noopener noreferrer"&gt;repositório do projeto no GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Embora seja uma aplicação bastante simples, ela forma a base de como um serviço da vida real pode ser construído utilizando Go para buscar e fornecer informações do CEP a partir de uma API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Melhorias
&lt;/h2&gt;

&lt;p&gt;Apesar de este ser um código que funciona e retorna o dado que esperamos, existem algumas coisas que podem ser melhoradas neste código.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tratamento de erros&lt;/strong&gt;: Quando um erro ocorrer, pode ser interessante retornar a mensagem de erro real ao invés de apenas um código de status HTTP para ajudar na depuração.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lembre-se de que esta não é uma boa prática para um ambiente de produção&lt;/strong&gt;, pois pode expor detalhes do sistema a usuários indesejados. &lt;/p&gt;

&lt;p&gt;Em um ambiente de produção, uma coisa que você pode fazer é logar o erro e retornar um ID de log para o cliente como uma referência para ele usar na abertura de um atendimento de suporte, por exemplo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Endpoint do servidor&lt;/strong&gt;: Atualmente o serviço está configurado para escutar todas as requisições na raiz ("/"). &lt;/p&gt;

&lt;p&gt;Poderia ser mais inteligente e útil ter um endpoint específico para essa funcionalidade como "/ceps" ou "/buscarCep". O exemplo não considerou isso justamente por ser um exemplo!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Validação do CEP&lt;/strong&gt;: Poderia ser interessante adicionar uma validação mais forte para o campo 'cep'. &lt;/p&gt;

&lt;p&gt;Atualmente, o código apenas verifica se tem 8 caracteres, mas pode existir um cenário onde a entrada tenha 8 caracteres mas não seja um CEP válido. 🤡&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testes&lt;/strong&gt;: Incluir testes de unidade e integração para garantir que o serviço está funcionando conforme esperado.&lt;/p&gt;

&lt;p&gt;Na verdade tudo isso deveria ter começado a partir da escrita de testes. &lt;em&gt;My bad&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goroutine no BuscaCep&lt;/strong&gt;: A função do &lt;code&gt;BuscaCep&lt;/code&gt; que chama um serviço externo poderia considerar utilizar uma goroutine para executar essa tarefa assincronamente.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verificações HTTP&lt;/strong&gt;: A resposta da função http.Get(url) pode vir com &lt;code&gt;statusCode não 200&lt;/code&gt;. Seria inteligente fazer essa verificação antes de ler o corpo da resposta.&lt;/p&gt;




&lt;p&gt;Agora sim, pronto!&lt;/p&gt;

&lt;p&gt;Talvez quando você ler este post, os arquivos no repositório já tenham sido alterados e algumas dessas (ou todas) melhorias implementadas.&lt;/p&gt;

&lt;p&gt;E se você tiver sugestões que colaborem com o aprendizado de outras pessoas sobre este mesmo assunto, fique a vontade para fazer um pull-request no GitHub.&lt;/p&gt;

&lt;p&gt;Até a próxima 🤘&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Benchmark Go: Marshal x Encoder com requisição http</title>
      <dc:creator>Marcelo Matz</dc:creator>
      <pubDate>Tue, 29 Aug 2023 17:46:11 +0000</pubDate>
      <link>https://dev.to/matzcoelho/benchmark-go-marshal-x-encoder-com-requisicao-http-481o</link>
      <guid>https://dev.to/matzcoelho/benchmark-go-marshal-x-encoder-com-requisicao-http-481o</guid>
      <description>&lt;p&gt;Este artigo tem a &lt;strong&gt;obrigação&lt;/strong&gt; de começar explicando que sim, eu sei que sistematicamente &lt;strong&gt;realizar requisições de rede dentro de um benchmark não é uma prática recomendada&lt;/strong&gt; devido à variabilidade e à falta de controle sobre a rede, que pode levar a resultados de benchmark inconsistentes. E provavelmente vai. Mas eu vou fazer mesmo assim.&lt;/p&gt;

&lt;h1&gt;
  
  
  Faz um Bench!
&lt;/h1&gt;

&lt;p&gt;Nos meus estudos em programação eu aprendi que, quando eu tenho dúvida sobre o que usar, testar é a melhor forma de entender o que faz mais sentido usar.&lt;/p&gt;

&lt;p&gt;Neste artigo eu vou falar sobre testes usando Marshal e Encoder, e também vou fazer a deserialização de um JSON usando Unmarshal e Decoder a partir de uma requisição HTTP.&lt;/p&gt;

&lt;h2&gt;
  
  
  Um pouco de história
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Quem é melhor, Marshal ou Encoder?
&lt;/h3&gt;

&lt;p&gt;Em Go, &lt;code&gt;json.Marshal&lt;/code&gt; e &lt;code&gt;json.NewEncoder&lt;/code&gt; são usados para converter a estrutura de dados em Go para JSON, mas eles são usados de maneiras diferentes.&lt;/p&gt;

&lt;p&gt;A função &lt;code&gt;json.Marshal&lt;/code&gt; retorna uma representação JSON da estrutura de dados Go na forma de uma []byte e um error caso ocorra algum. &lt;/p&gt;

&lt;p&gt;Por outro lado, json.NewEncoder pega um io.Writer (como um os.File ou http.ResponseWriter) e retorna um novo *json.Encoder que pode ser usado para transmissão de stream da estrutura de dados Go para o io.Writer em formato JSON. &lt;/p&gt;

&lt;p&gt;Aqui um exemplo usando &lt;strong&gt;json.Marshal&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "encoding/json"
    "fmt"
    "log"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    p := &amp;amp;Person{"Ada", 36}
    b, err := json.Marshal(p)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(string(b))
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Outro exemplo usando &lt;strong&gt;json.NewEncoder&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "encoding/json"
    "log"
    "os"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    p := &amp;amp;Person{"Ada", 36}
    err := json.NewEncoder(os.Stdout).Encode(p)
    if err != nil {
        log.Fatal(err)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ambas as amostras de código produzirão a mesma saída JSON &lt;code&gt;{"Name":"Ada","Age":36}&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Em resumo
&lt;/h3&gt;

&lt;p&gt;A principal diferença de desempenho entre json.Marshal e json.NewEncoder está na alocação de memória.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;json.Marshal&lt;/strong&gt; converte a estrutura de dados em Go em uma sequência JSON &lt;strong&gt;completamente na memória&lt;/strong&gt; e, em seguida, retorna essa sequência em formato []byte. &lt;/p&gt;

&lt;p&gt;Esta abordagem é rápida e simples, mas pode ser um problema se você estiver tentando processar uma grande quantidade de dados de uma vez - você pode facilmente ficar sem memória.&lt;/p&gt;

&lt;p&gt;Por outro lado, json.NewEncoder escreve a saída JSON diretamente para um io.Writer como um fluxo, por isso é mais eficiente em termos de memória. Ele não precisa alocar espaço para a estrutura de dados inteira em memória de uma só vez, então você pode processar volumes de dados muito maiores sem se preocupar com problemas de memória.&lt;/p&gt;

&lt;p&gt;Se você está manipulando uma &lt;strong&gt;pequena&lt;/strong&gt; quantidade de dados e precisa de uma sequência JSON para uso no programa, &lt;strong&gt;json.Marshal&lt;/strong&gt; é uma escolha adequada. &lt;/p&gt;

&lt;p&gt;Se você estiver processando uma &lt;strong&gt;grande&lt;/strong&gt; quantidade de dados ou quer enviar o JSON diretamente para um http.ResponseWriter ou para um arquivo, &lt;strong&gt;json.NewEncoder&lt;/strong&gt; é geralmente uma opção melhor &lt;em&gt;devido ao seu menor uso de memória&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No entanto, a diferença no desempenho e no uso de memória entre os dois provavelmente só será perceptível para estruturas de dados muito grandes. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Para a maioria dos usos diários, você pode usar o que achar mais conveniente e quando alguém perguntar para você qual é melhor, responda: depende!&lt;/p&gt;

&lt;h2&gt;
  
  
  Além do Go
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pacotes de terceiros que fazem a mão do JSON
&lt;/h3&gt;

&lt;p&gt;Existem outras opções e pacotes de terceiros disponíveis na linguagem Go para manipulação de JSON. Neste caso eu vou falar de uma em especial.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;jsoniter&lt;/strong&gt;: jsoniter é uma biblioteca que afirma ser compatível com encoding/json mas 4x a 6x mais rápida.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/json-iterator/go" rel="noopener noreferrer"&gt;O link para o repo do jsoniter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Usar o JsonIter em Go é simples como usar qualquer outro pacote externo.&lt;/p&gt;

&lt;p&gt;Aqui um exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "github.com/json-iterator/go"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    var json = jsoniter.ConfigCompatibleWithStandardLibrary
    p := &amp;amp;Person{"Ada", 36}
    b, err := json.Marshal(p)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(b))
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Se o desempenho for um problema crítico, você pode eventualmente considerar a escrita de suas próprias funções de serialização / des-serialização. No entanto, isso normalmente só é necessário em circunstâncias muito específicas e as diferenças de desempenho entre os pacotes prontos para uso são geralmente pequenas para a maioria dos casos de uso.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Em resumo nós temos os recursos nativos do Go onde podemos tanto usar o Marshal quanto o Encoder e podemos usar o jsoniter também com Marshal e Encoder.&lt;/p&gt;

&lt;p&gt;Vamos escrever um teste para comparar eles, fazendo uma requisição http para a API do &lt;a href="https://viacep.com.br/" rel="noopener noreferrer"&gt;ViaCep&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Como eu vou fazer uma requisição http, vou utilizar a deserialização com Unmarshal e Decoder. Bora!&lt;/p&gt;




&lt;h2&gt;
  
  
  Deserializando o JSON de um request HTTP
&lt;/h2&gt;

&lt;p&gt;O exemplo de código que vamos usar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "bytes"
    "encoding/json"
    "io/ioutil"
    "net/http"
    "testing"

    jsoniter "github.com/json-iterator/go"
)

type Info struct {
    Cep         string `json:"cep"`
    Logradouro  string `json:"logradouro"`
    Complemento string `json:"complemento"`
    Bairro      string `json:"bairro"`
    Localidade  string `json:"localidade"`
    Uf          string `json:"uf"`
    Unidade     string `json:"unidade"`
    Ibge        string `json:"ibge"`
    Gia         string `json:"gia"`
}

func fetchData(url string) ([]byte, error) {
    resp, err := http.Get(url)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    return ioutil.ReadAll(resp.Body)
}

func BenchmarkEncodingJsonUnmarshal(b *testing.B) {
    data, _ := fetchData("https://viacep.com.br/ws/01001000/json/")
    info := &amp;amp;Info{}
    for i := 0; i &amp;lt; b.N; i++ {
        if err := json.Unmarshal(data, &amp;amp;info); err != nil {
            b.Fatal(err)
        }
    }
}

func BenchmarkEncodingJsonDecoder(b *testing.B) {
    data, _ := fetchData("https://viacep.com.br/ws/01001000/json/")
    info := &amp;amp;Info{}
    for i := 0; i &amp;lt; b.N; i++ {
        if err := json.NewDecoder(bytes.NewBuffer(data)).Decode(&amp;amp;info); err != nil {
            b.Fatal(err)
        }
    }
}

func BenchmarkJsoniterUnmarshal(b *testing.B) {
    data, _ := fetchData("https://viacep.com.br/ws/01001000/json/")
    info := &amp;amp;Info{}
    var json = jsoniter.ConfigCompatibleWithStandardLibrary
    for i := 0; i &amp;lt; b.N; i++ {
        if err := json.Unmarshal(data, &amp;amp;info); err != nil {
            b.Fatal(err)
        }
    }
}

func BenchmarkJsoniterDecoder(b *testing.B) {
    data, _ := fetchData("https://viacep.com.br/ws/01001000/json/")
    info := &amp;amp;Info{}
    var json = jsoniter.ConfigCompatibleWithStandardLibrary
    for i := 0; i &amp;lt; b.N; i++ {
        if err := json.NewDecoder(bytes.NewBuffer(data)).Decode(&amp;amp;info); err != nil {
            b.Fatal(err)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em cada um desses benchmarks, estamos fazendo uma chamada GET para a API, obtendo os dados em um formato JSON, e em seguida deserializando esses dados JSON para uma instância do struct Info.&lt;/p&gt;

&lt;p&gt;Lembre-se de cuidar com carinho dos erros. Aqui estou ignorando o erro do fetchData para manter o foco na comparação de desempenho entre Unmarshal e Decoder. &lt;em&gt;O erro que erre!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Você pode acessar o &lt;a href="https://github.com/marcelomatz/trabalhando_com_json" rel="noopener noreferrer"&gt;repositório do código no GitHub&lt;/a&gt; e rodar o teste na sua máquina. Na minha máquina funcionou!&lt;/p&gt;

&lt;h3&gt;
  
  
  Os testes são:
&lt;/h3&gt;

&lt;p&gt;Nos benchmarks que estão no código do teste que foi feito, existem quatro operações sendo testadas: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a deserialização do JSON usando json.Unmarshal (BenchmarkEncodingJsonUnmarshal) &lt;/li&gt;
&lt;li&gt;a deserialização usando json.NewDecoder (BenchmarkEncodingJsonDecoder) &lt;/li&gt;
&lt;li&gt;a deserialização usando jsoniter.Unmarshal (BenchmarkJsoniterUnmarshal)&lt;/li&gt;
&lt;li&gt;deserialização usando jsoniter.NewDecoder (BenchmarkJsoniterDecoder)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Detalhe: As operações estão rodando em uma máquina Apple M1 (goos:darwin, goarch: arm64).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Os resultados mostram que &lt;strong&gt;jsoniter&lt;/strong&gt; (tanto Unmarshal quanto Decoder) é mais rápido que o pacote encoding/json padrão.
&lt;/h3&gt;

&lt;p&gt;Isso é consistente com a reputação de jsoniter de ser uma biblioteca de JSON mais rápida, já que foi projetada com o desempenho em mente.&lt;/p&gt;

&lt;h3&gt;
  
  
  Alguns dados do bench
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;BenchmarkEncodingJsonUnmarshal&lt;/strong&gt;: A operação de deserialização usando json.Unmarshal foi concluída em 2233 nanossegundos (ns) por operação. Foram realizadas 496503 operações.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BenchmarkEncodingJsonDecoder&lt;/strong&gt;: A operação de deserialização usando json.NewDecoder foi concluída em 2678 ns por operação. Foram realizadas 484986 operações. Esse número é maior do que Unmarshal possivelmente porque Decoder é mais adequado para fluxos de dados.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BenchmarkJsoniterUnmarshal&lt;/strong&gt;: A operação de deserialização usando jsoniter.Unmarshal foi concluída em 538.3 ns por operação. Foram realizadas 2000696 operações.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BenchmarkJsoniterDecoder&lt;/strong&gt;: A operação de deserialização usando jsoniter.NewDecoder foi concluída em 676.8 ns por operação. Foram realizadas 1633261 operações.&lt;/p&gt;

&lt;p&gt;Observe que, apesar de jsoniter ser mais rápido que json, existem outros aspectos a considerar ao escolher qual usar. &lt;/p&gt;

&lt;p&gt;Alguns dos aspectos mais notáveis seriam a compatibilidade da API (a API do json é estável desde Go 1, enquanto a de jsoniter pode não ser) e a quantidade de recursos disponíveis (há provavelmente mais tutoriais, exemplos de código, e respostas do StackOverflow para json do que para jsoniter).&lt;/p&gt;

&lt;p&gt;É isso! Se você gostou (ou não) considere deixar um comentário.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>go</category>
      <category>benchmark</category>
      <category>testing</category>
    </item>
    <item>
      <title>Manipulando arquivos: um CRUD de arquivos em Go</title>
      <dc:creator>Marcelo Matz</dc:creator>
      <pubDate>Mon, 28 Aug 2023 22:31:46 +0000</pubDate>
      <link>https://dev.to/matzcoelho/manipulando-arquivos-criando-um-file-crud-em-go-m9a</link>
      <guid>https://dev.to/matzcoelho/manipulando-arquivos-criando-um-file-crud-em-go-m9a</guid>
      <description>&lt;h1&gt;
  
  
  Como Criar um CRUD de arquivos em Go
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Um guia básico e passo a passo
&lt;/h2&gt;

&lt;p&gt;Uma das coisas que dev mais faz no seu dia a dia é resolver problemas aplicando os fundamentos da programação. &lt;/p&gt;

&lt;p&gt;Um destes fundamentos é &lt;strong&gt;a capacidade de ler e escrever em arquivos.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Quem trabalha desenvolvendo software, acaba trabalhando com manipulação de arquivos em algum momento.&lt;/p&gt;

&lt;p&gt;Neste artigo eu vou mostrar como criar um &lt;strong&gt;CRUD&lt;/strong&gt; (Create, Read, Update, Delete) &lt;strong&gt;de arquivo&lt;/strong&gt; usando a linguagem de programação Go.&lt;/p&gt;

&lt;p&gt;Vale ressaltar que neste exemplo eu vou usar os próprios recursos do Go sem a necessidade importar nenhuma biblioteca externa para o meu software.&lt;/p&gt;

&lt;p&gt;Caso você queria pesquisar mais a fundo sobre cada biblioteca usada na criação deste exemplo, você pode &lt;a href="https://pkg.go.dev/std" rel="noopener noreferrer"&gt;consultar a documentação da Standard Library do Go&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Se você preferir ir direto para o repositório do código ao invés de ler o artigo, você pode acessar o&lt;/strong&gt; &lt;a href="https://github.com/marcelomatz/manipulando_arquivos_em_go" rel="noopener noreferrer"&gt;repositório no GitHub&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Show me the code
&lt;/h2&gt;

&lt;p&gt;O ponto de partida que qualquer software em Go é a partir da função main contida no pacote main. Eu vou escrever todo o código dentro da mesma função &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Abaixo temos a estrutura base do nosso software:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
)

func main() {
    // Agora só falta implementar
    // Duas barras e um texto indica um comentário
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  O CRUD na prática
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create
&lt;/h3&gt;

&lt;p&gt;Eu vou começar implementando o &lt;strong&gt;C&lt;/strong&gt;reate do CRUD e para fazer isso em Go eu vou usar o método nativo da linguagem &lt;code&gt;os.Create()&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O pacote &lt;code&gt;os&lt;/code&gt; do Go permite acessar diversos recursos do sistema operacional, e como nós queremos trabalhar com arquivos, nada mais justo do que usar o pacote que permite isso.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;f, err := os.Create("test.txt")
if err != nil {
    panic(err)
}
// Não esqueça de fechar o arquivo quando a criação for concluída.
defer func(f *os.File) {
    err := f.Close()
    if err != nil {
        panic(err)
    }
}(f)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dentro da função Main nós temos uma variável &lt;code&gt;f&lt;/code&gt; que recebe como valor o &lt;code&gt;os.Create()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Note que além da variável &lt;code&gt;f&lt;/code&gt; existe uma outra variável chamada &lt;code&gt;err&lt;/code&gt; que também foi criada.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Em Go quando nós temos &lt;code&gt;algumaCoisa := "valorDeAlgumaCoisa"&lt;/code&gt; significa que nós estamos criando uma variável e ao mesmo tempo estamos atribuindo um valor. O &lt;code&gt;:=&lt;/code&gt; é o operador Marmota (logo do Go) usado para criação e inferência de tipo.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  O processo se resume em:
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1) Criar a variável &lt;code&gt;f&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;(ou file, ou arquivo ou o nome que você quiser) e criar também uma variável para receber o erro &lt;code&gt;err&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;O método (função) &lt;code&gt;Create&lt;/code&gt; do pacote &lt;code&gt;os&lt;/code&gt; do Go funciona da seguinte forma: ele recebe um &lt;em&gt;nome&lt;/em&gt; como parâmetro e retorna &lt;strong&gt;dois valores&lt;/strong&gt;: O primeiro retorno é o arquivo em si (no caso um ponteiro para o arquivo, mas não vou entrar no mérito dos ponteiros aqui) e também recebe como retorno um erro.&lt;/p&gt;

&lt;h4&gt;
  
  
  2) Usar o método &lt;code&gt;defer&lt;/code&gt; para garantir que o arquivo vai ser fechado depois que ele for criado.
&lt;/h4&gt;

&lt;p&gt;O &lt;code&gt;defer&lt;/code&gt; em Go é utilizado para garantir que uma função seja executada &lt;strong&gt;posteriormente&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A instrução &lt;code&gt;defer&lt;/code&gt; &lt;strong&gt;agenda uma função&lt;/strong&gt; a ser chamada após a função que a contém ser concluída.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pode parecer confuso, mas você vai perceber que em outras palavras, a função é "adiada" até que o resto do código seja executado. &lt;/p&gt;

&lt;p&gt;Um uso comum para defer é justamente para fechar um arquivo, garantindo que, &lt;strong&gt;independentemente do que acontecer no código após a abertura do arquivo&lt;/strong&gt;, ele (o arquivo) será fechado quando a função for terminada. &lt;br&gt;
Por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;file, err := os.Open("file.txt")
if err != nil {
    log.Fatal(err)
}

defer file.Close()

// Outras operações no arquivo...
// O arquivo será fechado quando a função terminar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste exemplo, &lt;code&gt;file.Close()&lt;/code&gt; só será chamado depois que o resto do código na função for executado. &lt;strong&gt;Isso é útil porque mesmo se uma operação subsequente no arquivo resultar em um erro e você retornar da função mais cedo do que o esperado, o arquivo ainda será fechado corretamente.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Defer e Closure
&lt;/h3&gt;

&lt;p&gt;Outra maneira de usar o defer neste caso é em conjunto com uma função anônima. &lt;strong&gt;Closure é uma função anônima.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Muitas vezes é recomendado usar closures com a declaração defer, principalmente quando estamos lidando com operações que também envolvem erros, &lt;strong&gt;como fechamento de arquivos ou conexões em Go.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Um dos principais motivos para combinar &lt;code&gt;defer&lt;/code&gt; com uma closure é que &lt;em&gt;a closure pode acessar e manipular&lt;/em&gt; as variáveis definidas no escopo onde ela foi criada.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Portanto, ela pode lidar com valores ou estados que possam ter mudado ao longo do tempo antes de o defer ser realmente executado.&lt;br&gt;
Aqui está um exemplo de fechamento de um arquivo usando closure e defer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;f, err := os.Open("file.txt")
if err != nil {
    log.Fatal(err)
}

defer func(f *os.File) {
    if err := f.Close(); err != nil {
        log.Fatal(err) // ou qualquer outra manipulação de erro
    }
}(f)

// Outras operações no arquivo...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em resumo, após criarmos um arquivo usando &lt;code&gt;os.Create("nomeDoArquivo.extensaoDoArquivo")&lt;/code&gt; nós precisamos fechar ele. De acordo com a implementação do método na standard library, na hora que passamos o nome do arquivo como parâmetro para a função Create, caso o arquivo não exista ele vai ser criado e, caso ele já exista, o Go faz um &lt;em&gt;truncate&lt;/em&gt; do arquivo.&lt;/p&gt;




&lt;h3&gt;
  
  
  Read
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Ler do Arquivo
&lt;/h4&gt;

&lt;p&gt;A leitura do arquivo é feita em duas etapas. Primeiro, abrimos o arquivo com &lt;code&gt;os.Open()&lt;/code&gt; e em seguida lemos o arquivo utilizando &lt;code&gt;bufio.NewReader()&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;f, err := os.Open("test.txt")
if err != nil {
    panic(err)
}
defer func(f *os.File) {
    err := f.Close()
    if err != nil {
        panic(err)
    }
}(f)

reader := bufio.NewReader(f)
buffer := make([]byte, 10)
for {
    n, err := reader.Read(buffer)
    if err != nil &amp;amp;&amp;amp; err != io.EOF {
        panic(err)
    }
    if n == 0 {
        break
    }
    fmt.Print(string(buffer[:n]))
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora mais duas variáveis foram criadas. Uma &lt;code&gt;reader&lt;/code&gt; e uma &lt;code&gt;buffer&lt;/code&gt;. _Você pode abrir um arquivo sem buffer, mas lembre-se que dependendo do tamanho do arquivo ele pode exceder a memória disponível e acabe gerando um erro.&lt;/p&gt;

&lt;p&gt;A variável &lt;code&gt;reader&lt;/code&gt; agora armazena o retorno do método &lt;code&gt;bufio.NewReader(f)&lt;/code&gt; onde o &lt;code&gt;f&lt;/code&gt; nós estamos passando como parâmetro para este método.&lt;/p&gt;

&lt;p&gt;O mais legal de trabalhar com buffer é você poder definir &lt;em&gt;o tamanho da fatia&lt;/em&gt; que você quer ler de cada vez. No exemplo eu estou usando o método &lt;code&gt;make&lt;/code&gt; para criar um &lt;code&gt;slice de byte&lt;/code&gt; de tamanho &lt;code&gt;10&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;buffer := make([]byte, 10)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A função &lt;code&gt;make&lt;/code&gt; é função built-in do Go que aloca e inicializa um objeto do tipo slice, map ou char. No caso eu estou usando o tipo slice.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Você pode consultar a &lt;a href="https://pkg.go.dev/go/types" rel="noopener noreferrer"&gt;documentação do Go&lt;/a&gt; para saber mais sobre o pacote de tipos em Go.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Continuando com a explicação do exemplo, depois disso eu uso um laço &lt;code&gt;for&lt;/code&gt; para fazer algumas coisas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;n, err := reader.Read(buffer)&lt;/code&gt; Aqui eu estou acessando o método Read da função &lt;code&gt;bufio.NewReader(f)&lt;/code&gt; que eu usei para criar o meu reader e salvando na variável &lt;code&gt;n&lt;/code&gt;. _A variável de erro eu já expliquei antes como funciona.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Observe no código exemplo como lidamos com o &lt;code&gt;io.EOF&lt;/code&gt; (End of File).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if err != nil &amp;amp;&amp;amp; err != io.EOF {
        panic(err)
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;É importante lembrar de fazer isso &lt;strong&gt;porque a leitura pode retornar io.EOF a qualquer momento&lt;/strong&gt;, por isso já tratamos isso no &lt;code&gt;for&lt;/code&gt; e é assim que nós sabemos quando terminamos de ler o arquivo.&lt;/p&gt;

&lt;p&gt;Sobre o &lt;code&gt;io.EOF&lt;/code&gt; (End Of File): ele é um erro que é comum em operações de arquivo e é usado para indicar que o fim de um arquivo foi atingido.&lt;/p&gt;

&lt;p&gt;Como uma &lt;strong&gt;convenção em programação&lt;/strong&gt;, sempre que uma função está lendo de um arquivo e &lt;em&gt;atinge o fim do arquivo&lt;/em&gt;, &lt;strong&gt;essa função retorna io.EOF&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Isso é útil para que o código que chamou a função de leitura possa saber quando parar de ler.&lt;/p&gt;

&lt;p&gt;O nosso exemplo é bastante simples mas ele mostra como usamos o &lt;code&gt;io.Reader&lt;/code&gt; (uma interface que abstrai a leitura de dados de uma fonte).&lt;/p&gt;

&lt;p&gt;Nós usamos um loop (&lt;code&gt;for&lt;/code&gt;) para tentar ler &lt;code&gt;10 bytes&lt;/code&gt; do &lt;code&gt;reader&lt;/code&gt; de cada vez em nosso &lt;code&gt;buffer&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Se o reader.Read() encontrar um erro que não seja io.EOF, o programa entra em pânico. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Uma coisa que eu sempre gostei em Go foi poder definir que ele vai entrar em pânico caso algum erro aconteça porque literalmente a função que trata isso se chama &lt;code&gt;panic&lt;/code&gt; 😂&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Se nenhum byte for lido (n == 0), isso significa que atingimos io.EOF e o arquivo não tem mais nada a ser lido, então saímos do loop. &lt;/p&gt;

&lt;p&gt;Caso contrário, processamos os bytes que foram lidos com sucesso.&lt;/p&gt;

&lt;p&gt;Então, resumindo, &lt;code&gt;io.EOF&lt;/code&gt; é usado em Go (e muitas outras linguagens) para sinalizar que a leitura de um arquivo ou outra fonte de entrada chegou ao fim. Ele é útil para controlar loops e outras estruturas que continuam a ler até que não haja mais nada para ler.&lt;/p&gt;




&lt;h3&gt;
  
  
  Update
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Escrever no Arquivo
&lt;/h4&gt;

&lt;p&gt;Depois de criar o arquivo, podemos escrever nele. Para fazer isso, utilizamos a função f.Write(), que aceita uma fatia de bytes como argumento.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;size, err := f.Write([]byte("Criando conteúdo do arquivo"))
if err != nil {
    panic(err)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assegure-se de sincronizar os dados no disco usando &lt;code&gt;f.Sync()&lt;/code&gt; para garantir que todos os dados pendentes sejam efetivamente escritos no arquivo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;err = f.Sync()
if err != nil {
    panic(err)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Escrever em um arquivo é algo bem simples. No exemplo eu usei uma variável chamada &lt;code&gt;size&lt;/code&gt; para armazenar o retorno da função Write e uma variável de erro, como já de costume.&lt;/p&gt;

&lt;p&gt;Abaixo eu mostro como imprimir no console essa informação usando o pacote &lt;code&gt;fmt&lt;/code&gt; e a função &lt;code&gt;Printf&lt;/code&gt; para formatar a saída de texto usando o &lt;code&gt;%s&lt;/code&gt;(de string) que vai ser substituído pelo conteúdo do arquivo, convertido em string.&lt;/p&gt;

&lt;p&gt;Além disso eu também mostro o tamanho do arquivo em bytes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fmt.Printf("Tamanho: %d bytes\n", size)
    fmt.Printf("Conteúdo do arquivo: %s\n", string(arquivo))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Existe um outro método chamado writeString onde eu não precisaria passar um slice de bytes, porém, entretanto, contudo, eu teria que garantir que em 100% das vezes o que tipo de dado que vai trafegar ali é do tipo string. Se eu tenho a opção de trabalhar com uma cadeia de bytes, sejam eles em algum momento um string ou não, eu vou optar por isso.&lt;/p&gt;

&lt;p&gt;De qualquer forma, escrever dados em um arquivo é algo que se torna muito fácil quando aproveitamos os recursos da linguagem.&lt;/p&gt;




&lt;h3&gt;
  
  
  Delete
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Apagando um arquivo
&lt;/h4&gt;

&lt;p&gt;Apagar um arquivo usando Go é extremamente simples. Para deletar um arquivo, usamos a função os.Remove().&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;err = os.Remove("test.txt")
if err != nil {
    panic(err)
}
fmt.Println("\nArquivo deletado com sucesso!")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deployando
&lt;/h3&gt;

&lt;p&gt;Neste tutorial eu te mostrei como, fundamentalmente, fazer operações CRUD em arquivos no Go. &lt;/p&gt;

&lt;p&gt;Abaixo eu deixo um exemplo do código completo. No início do post tem o link para o repositório no GitHub.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
)

func main() {
    // Criar um novo arquivo
    f, err := os.Create("test.txt")
    if err != nil {
        panic(err)
    }
    defer func(f *os.File) {
        err := f.Close()
        if err != nil {
            panic(err)
        }
    }(f)

    // Escrevendo no arquivo criado
    size, err := f.Write([]byte("Criando conteúdo do arquivo"))
    if err != nil {
        panic(err)
    }

    // Sincroniza os dados no disco
    err = f.Sync()
    if err != nil {
        panic(err)
    }

    arquivo, err := os.ReadFile("test.txt")
    if err != nil {
        panic(err)
    }

    fmt.Println("Arquivo criado com sucesso!")
    fmt.Printf("Tamanho: %d bytes\n", size)
    fmt.Printf("Conteúdo do arquivo: %s\n", string(arquivo))

    // Abrindo um arquivo existente
    f2, err := os.Open("test.txt")
    if err != nil {
        panic(err)
    }
    defer func(arquivo2 *os.File) {
        err := arquivo2.Close()
        if err != nil {
            panic(err)
        }
    }(f2)

    // Lendo arquivo usando bufio
    reader := bufio.NewReader(f2)
    buffer := make([]byte, 10)
    for {
        n, err := reader.Read(buffer)
        if err != nil &amp;amp;&amp;amp; err != io.EOF {
            panic(err)
        }
        if n == 0 {
            break
        }
        fmt.Print(string(buffer[:n]))
    }

    // Deletando um arquivo
    /*
        err = os.Remove("test.txt")
        if err != nil {
            panic(err)
        }
        fmt.Println("\nArquivo deletado com sucesso!")
    */
}

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

&lt;/div&gt;



&lt;p&gt;Assim como em qualquer linguagem de programação, existem muitas nuances que nós podemos explorar mas eu considero este um ótimo ponto de partida. &lt;/p&gt;

&lt;p&gt;Espero que este guia tenha sido útil e encorajo a todos a continuar explorando e aprendendo Go!&lt;/p&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>github</category>
    </item>
  </channel>
</rss>
