<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Vue.js - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Aprenda a codificar - de graça. Tutoriais de programação em Python, JavaScript, Linux e muito mais. ]]>
        </description>
        <link>https://www.freecodecamp.org/portuguese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Vue.js - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/portuguese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 23 May 2026 08:28:35 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/portuguese/news/tag/vue-js/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Como usar props no Vue.js ]]>
                </title>
                <description>
                    <![CDATA[ Escrito por: Joel Olawanle Usamos props para passar informações/dados de um componente pai para componentes filhos. Neste artigo, vou explicar tudo o que você precisa saber sobre props e por que você deve usar props no Vue.js. Aqui está um breve resumo do que vamos cobrir neste guia:  * ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-usar-props-no-vue-js/</link>
                <guid isPermaLink="false">66fa124c9d6e9804088f0db9</guid>
                
                    <category>
                        <![CDATA[ Vue.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Rosa ]]>
                </dc:creator>
                <pubDate>Mon, 30 Sep 2024 03:05:46 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/09/Yellow-and-Purple-Geometric-Covid-19-General-Facts-Twitter-Post.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-use-props-in-vuejs/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Use Props in Vue.js</a>
      </p><p>Escrito por: Joel Olawanle</p><p>Usamos <em>props </em>para passar informações/dados de um componente pai para componentes filhos. Neste artigo, vou explicar tudo o que você precisa saber sobre <em>props</em> e por que você deve usar <em>props</em> no Vue.js.</p><p>Aqui está um breve resumo do que vamos cobrir neste guia:</p><ul><li>O que são <em>props </em>no Vue.js?</li><li>Como registrar <em>props </em>dentro de um componente</li><li>Como trabalhar com várias <em>props</em></li><li>Tipos de <em>props </em>no Vue.js</li><li>Como passar dados para <em>props</em></li><li>Como passar funções para <em>props</em></li><li>Como validar <em>props</em></li><li>Como definir valores padrão para <em>props</em></li></ul><h2 id="o-que-s-o-as-props-no-vue-js">O que são as <em>props </em>no Vue.js?</h2><p>"Props" é uma palavra-chave especial que significa <strong>propriedades</strong>. Elas podem ser registradas em um componente para passar dados de um componente pai para um de seus componentes filhos.</p><p>É muito mais fácil de usar em comparação com as bibliotecas de gerenciamento de estado, como o vuex, para aplicações do Vue.js.</p><p>Os dados em <em>props</em> só podem fluir em um sentido – de cima, ou do componente pai, para baixo, ou para os componentes filhos. Isso simplesmente significa que você não pode passar dados de um filho para um pai.</p><p>Outra coisa a se ter em mente é que <em>props</em> são apenas para leitura e não podem ser modificadas pelo componente filho porque é o componente pai quem "possui" esse valor.</p><p>Vamos equilibrar as coisas agora – os componentes pais passam <em>props</em> para os componentes filhos enquanto os componentes filhos emitem eventos para os componentes pais.</p><h2 id="como-registrar-props-em-um-componente">Como registrar <em>props </em>em um componente</h2><p>Vamos agora dar uma olhada em como podemos registrar <em>props </em>dentro de um componente.</p><pre><code>Vue.component('user-detail', {
  props: ['name'],
  template: '&lt;p&gt;Hi {{ name }}&lt;/p&gt;'
})
.js
</code></pre><p>ou, em um componente de arquivo único do Vue:</p><pre><code>&lt;template&gt;
  &lt;p&gt;{{ name }}&lt;/p&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  props: ['name']
}
&lt;/script&gt;
</code></pre><p>No código acima, registramos uma <em>prop </em>chamada <code>name</code> que podemos chamar na seção de <em>template </em>da nossa aplicação.</p><p>Observação: este é o componente filho e essa <em>prop </em>vai receber dados do componente pai. Vou explicar isso mais adiante.</p><h2 id="como-trabalhar-com-v-rias-props">Como trabalhar com várias <em>props</em></h2><p>Você pode ter mais de uma <em>prop </em>adicionando-as ao array de <em>props</em>, assim:</p><pre><code>Vue.component('user-detail', {
  props: ['firstName', 'lastName'],
  template: '&lt;p&gt;Hi {{ firstName }} {{ lastName }}&lt;/p&gt;'
})
</code></pre><p>ou, em um componente de arquivo único do Vue:</p><pre><code>&lt;template&gt;
  &lt;p&gt;Hi {{ firstName }} {{ lastName }}&lt;/p&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  props: [
    'firstName', 
    'lastName'
  ],
}
&lt;/script&gt;
</code></pre><h2 id="tipos-de-props-no-vue-js">Tipos de <em>props </em>no Vue.js</h2><p>Para especificar o tipo de <em>prop</em> que você deseja usar no Vue, você usará um objeto em vez de um array. Você usará o nome da propriedade como a chave de cada propriedade e o tipo como o valor.</p><p>Se o tipo de dado passado não corresponder ao tipo da <em>prop</em>, o Vue envia um alerta (em modo de desenvolvimento) no console com um aviso. Os tipos válidos que você pode usar são:</p><ul><li>String</li><li>Number</li><li>Boolean</li><li>Array</li><li>Object</li><li>Date</li><li>Function</li><li>Symbol</li></ul><pre><code>Vue.component('user-detail', {
  props: {
    firstName: String,
    lastName: String
  },
  template: '&lt;p&gt;Hi {{ firstName }} {{ lastName }}&lt;/p&gt;'
})
</code></pre><p>ou, em um componente de arquivo único do Vue:</p><pre><code>&lt;template&gt;
  &lt;p&gt;Hi {{ firstName }} {{ lastName }}&lt;/p&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  props: {
    firstName: String,
    lastName: String
  },
}
&lt;/script&gt;
</code></pre><h2 id="como-passar-dados-para-props-no-vue">Como passar dados para <em>props </em>no Vue</h2><p>O principal objetivo de usar <em>props </em>é passar dados/informações para baixo. Você pode passar seu valor como uma propriedade de dados usando <em>v-bind</em>, como neste código:</p><pre><code>&lt;template&gt;
  &lt;ComponentName :title=title /&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  //...
  data() {
    return {
      title: 'Entendendo props no Vue.js'
    }
  },
  //...
}
&lt;/script&gt;
</code></pre><p>ou como um valor estático, assim:</p><pre><code>&lt;ComponentName title="Entendendo props no Vue.js" /&gt;
</code></pre><p>Suponha que estamos criando uma aplicação que tem vários botões com diferentes cores de texto/fundo. Em vez de repetir a sintaxe do botão em todos os nossos arquivos, é melhor criar um componente de botão e então passar as cores de texto/fundo como <em>props</em>.</p><p>Aqui está o componente pai:</p><pre><code>&lt;template&gt;
  &lt;div id="app"&gt;
    &lt;Button :name='btnName' bgColor='red' /&gt;
    &lt;Button :name='btnName' bgColor='green' /&gt;
    &lt;Button :name='btnName' bgColor='blue' /&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import Button from './components/Button'

export default {
  name: 'App',
  data(){
    return{
      btnName:"Joel",
    }
  },
  components: {
    Button
  }
}
&lt;/script&gt;
</code></pre><p>Aqui está o componente filho:</p><pre><code>&lt;template&gt;
  &lt;button class="btn" :style="{backgroundColor:bgColor}"&gt;{{name}}&lt;/button&gt;
&lt;/template&gt;
&lt;script&gt;
export default {
  name: 'Button',
  props:{
    name:String,
    bgColor:String
  }
}
&lt;/script&gt;
</code></pre><p>O código acima mostra como usar tanto a propriedade de dados quanto valores estáticos quando você está recebendo dados de um componente pai e usando esses dados em um componente filho.</p><p><strong>Observação:</strong> você também pode usar um operador ternário dentro do valor da <em>prop</em> para verificar uma condição verdadeira e passar um valor que dependa dela.</p><pre><code>&lt;template&gt;
  &lt;div id="app"&gt;
    &lt;Button :tagUser="signedUp ? 'Logout' : 'Login'" bgColor='red' /&gt;
  &lt;/div&gt;
&lt;/template&gt;
&lt;script&gt;
import Button from './components/Button'
export default {
  name: 'App',
  data(){
    return{
      signedUp: true,
    }
  },
  components: {
    Button
  }
}
&lt;/script&gt;
</code></pre><h2 id="como-passar-fun-es-para-props">Como passar funções para props</h2><p>Passar uma função ou um método para um componente filho como <em>prop </em>é relativamente simples. Basicamente, é o mesmo processo que passar qualquer outra variável.</p><p>Há razões, porém, pelas quais você não deve usar <em>props</em> como funções – em vez disso, você deve usar <em>emit</em>. <a href="https://michaelnthiessen.com/pass-function-as-prop/">Este artigo</a> (texto em inglês) explica corretamente o porquê.</p><pre><code>&lt;template&gt;
  &lt;ChildComponent :function="newFunction" /&gt;
&lt;/template&gt;
</code></pre><pre><code>&lt;script&gt;
export default {
  methods: {
    newFunction() {
      // ...
    }
  }
};
&lt;/script&gt;
</code></pre><h2 id="como-validar-props-no-vue">Como validar props no Vue</h2><p>O Vue torna a validação de <em>props </em>muito fácil. Tudo o que você precisa fazer é adicionar a chave <em>required </em>e seu valor à <em>prop</em>. Podemos validar tanto pelo tipo da <em>prop</em> quanto pelo uso de <code>required</code>:</p><pre><code>props: {
  name: {
    type: String,
    required: true
  }
}
</code></pre><h2 id="como-definir-valores-padr-o-para-props">Como definir valores padrão para <em>props</em></h2><p>Antes de concluir este artigo, vamos agora ver como definir valores padrão para nossas <em>props</em>. Valores padrão são renderizados se o componente filho não conseguir obter dados do componente pai.</p><p>O Vue permite que você especifique um valor padrão, assim como especificamos <code>required</code> anteriormente.</p><pre><code>props: {
  name: {
    type: String,
    required: true,
    default: 'John Doe'
  },
  img: {
    type: String,
    default: '../image-path/image-name.jpg',
   },
}
</code></pre><p>Você também pode definir o valor padrão como um objeto. Esse pode ser uma função que retorna um valor apropriado, em vez de ser o valor real.</p><h2 id="conclus-o">Conclusão</h2><p>Neste artigo, aprendemos o que as <em>props</em> fazem e como elas funcionam no Vue.js.</p><p>Em resumo, usamos <em>props</em> para passar dados dos componentes pais para os componentes filhos. O componente filho também emite eventos para os componentes pais caso você precise enviar dados/eventos do filho para o componente pai.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/09/image-50.png" class="kg-image" alt="image-50" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/09/image-50.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/09/image-50.png 790w" sizes="(min-width: 720px) 720px" width="790" height="646" loading="lazy"></figure><p>Obrigado pela leitura!</p><p><strong>Links úteis (em inglês)</strong></p><ul><li><a href="https://flaviocopes.com/vue-props/">Vue.js Component Props - flaviocopes</a></li><li><a href="https://vuejs.org/v2/guide/components-props.html">Props - documentação do Vue</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como criar uma SPA com Vue.js e C# usando .NET Core ]]>
                </title>
                <description>
                    <![CDATA[ Digamos que você é um desenvolvedor de front-end ou que tenha trabalhado mais com o front-end recentemente. Às vezes, você acaba usando algumas tecnologias de back-end, mas tende a ficar na sua zona de conforto, provavelmente no universo do JavaScript. É possível que você tenha criado uma pequena API com ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-criar-uma-spa-com-vue-js-e-c-sharp-usando-net-core/</link>
                <guid isPermaLink="false">63bae2e2ad276e05ed7570a2</guid>
                
                    <category>
                        <![CDATA[ Vue.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gabriel Galdino ]]>
                </dc:creator>
                <pubDate>Wed, 29 Mar 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/dashboard-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-build-an-spa-with-vuejs-and-c-using-net-core/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Build an SPA with Vue.js and C# Using .NET Core</a>
      </p><p>Digamos que você é um desenvolvedor de <em>front-end</em> ou que tenha trabalhado mais com o <em>front-end</em> recentemente.</p><p>Às vezes, você acaba usando algumas tecnologias de <em>back-end</em>, mas tende a ficar na sua zona de conforto, provavelmente no universo do JavaScript. É possível que você tenha criado uma pequena API com Python em algum momento também.</p><p>Você, no entanto, nunca tocou na <em>stack</em> de tecnologias moderna da família .NET.</p><p>Nesse sentido, este tutorial vai guiá-lo, passo a passo, na criação de uma aplicação moderna de <em>Single-Page Application</em> (SPA), que usará o Vue.js para o <em>front-end</em> e o .NET Core (C#) para o <em>back-end</em>.</p><p>Além disso, veremos como escrever alguns testes, tanto de unidade quanto de integração, a fim de cobrir a funcionalidade do <em>front-end</em> e do <em>back-end</em> (ao menos, parcialmente).</p><p>Se você quiser pular a leitura, aqui está o <a href="https://github.com/mihailgaberov/pizza-app/blob/master/">repositório do GitHub</a> com um <a href="https://github.com/mihailgaberov/pizza-app/blob/master/README.md">README</a> detalhado.</p><h2 id="o-que-vamos-criar"><strong>O que vamos criar?</strong></h2><p>Vamos criar uma aplicação da web na qual os usuários podem fazer login/se cadastrar e nos dizer o quanto eles gostam de pizza ao pressionar um botão dizendo "I love it" ('Eu adoro pizza').</p><p>Não há restrições de quantas vezes cada usuário pode nos mostrar o quanto gosta de pizza. O único requisito é que apenas usuários logados podem votar.</p><p>Na página inicial, junto com os botões de login/cadastro, colocaremos um pequeno gráfico de barras, exibindo os X usuários com a maior apreciação (no eixo X) e o número de votos (no eixo Y)."</p><h2 id="instala-o"><strong>Instalação</strong></h2><p>Vamos começar pelo <em>front-end</em>. Faz mais sentido construir primeiro as partes visíveis da nossa aplicação. Assim, construiremos o nosso <em>front-end</em> com uma das bibliotecas de <em>front-end</em> mais famosas do mercado: o Vue.js.</p><h3 id="como-configurar-o-front-end"><strong>Como configurar o <em>front-end</em></strong></h3><p>Para instalar e configurar inicialmente o nosso <em>front-end</em> com Vue.js, vamos usar a CLI do Vue. Trata-se de uma ferramenta de linha de comando padrão para o desenvolvimento de aplicativos em Vue.js.</p><blockquote>Nota da tradução: CLI é a abreviação para <em>Command Line Interface</em>, ou interface da linha de comando, em português. </blockquote><p>Para instalá-la, use o comando abaixo. Observe que todos os comandos neste tutorial usam o NPM, que você precisa ter instalado na sua máquina para acompanhar.</p><figure class="kg-card kg-code-card"><pre><code class="language-bash">npm install -g @vue/cli</code></pre><figcaption>Instalando a CLI do Vue</figcaption></figure><p>Depois de instalar a CLI do Vue com sucesso, poderemos utilizá-la para instalar e configurar o Vue.js. Vamos fazer isso por meio deste processo:</p><p>1º Passo: crie um diretório de projeto vazio e abra-o com os seguintes abaixo.</p><figure class="kg-card kg-code-card"><pre><code>mkdir pizza-app
cd pizza-app</code></pre><figcaption>Criando um novo diretório de projeto vazio</figcaption></figure><p>Passo 2: dentro do diretório raiz do projeto, execute o comando a seguir.</p><figure class="kg-card kg-code-card"><pre><code class="language-bash">vue create frontend</code></pre><figcaption>Criando a parte de <em>front-end</em> do app</figcaption></figure><p>Em seguida, nas opções fornecidas, selecione o seguinte:</p><ul><li>Seleção manual de recursos "<em>Manually select features</em>".</li></ul><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-52.png" class="kg-image" alt="image-52" width="407" height="201" loading="lazy"><figcaption>Instalação do Vue.js – seleção manual dos recursos</figcaption></figure><ul><li>Babel</li><li>Router</li><li>Pré-processadores do CSS (<em>CSS-Preprocessors</em>, como o SASS)</li></ul><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-53.png" class="kg-image" alt="image-53" width="401" height="331" loading="lazy"><figcaption>Instalação do Vue.js – seleção dos recursos</figcaption></figure><p>Em seguida, selecione a versão 2.x na próxima tela:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-54.png" class="kg-image" alt="image-54" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-54.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-54.png 963w" width="963" height="223" loading="lazy"><figcaption>Selecionando a versão 2.x</figcaption></figure><blockquote>Nota de tradução: o Vue.js, no momento da tradução, está em sua versão 3 e o suporte à versão 2 terminará ao final deste ano. Neste momento, no entanto, ainda é possível realizar as configurações de acordo com este tutorial seguindo as instruções.</blockquote><p>Em seguida, selecione &nbsp;'<em>Use history mode for router?</em>' e '<em>Sass/SCSS (with node-sass)</em>', assim:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-57.png" class="kg-image" alt="image-57" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-57.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-57.png 963w" width="963" height="277" loading="lazy"></figure><ul><li>Linter / Formatter</li></ul><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-58.png" class="kg-image" alt="image-58" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-58.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-58.png 957w" width="957" height="279" loading="lazy"></figure><ul><li>Teste de unidade com Jest</li></ul><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-59.png" class="kg-image" alt="image-59" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-59.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-59.png 965w" width="965" height="297" loading="lazy"></figure><ul><li>Teste de ponta a ponta (E2E) com Cypress</li></ul><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-60.png" class="kg-image" alt="image-60" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-60.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-60.png 957w" width="957" height="315" loading="lazy"></figure><p>Depois desse último passo, finalize o processo de instalação com as opções padrão.</p><p>Agora estamos prontos para executar a aplicação usando os seguintes comandos a partir da pasta raiz do projeto:</p><pre><code class="language-bash">cd frontend
npm run serve</code></pre><p>Depois que o app estiver em execução, você poderá vê-lo no seu navegador em http://localhost:8080:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/welcome-to-your-vuejs-app.png" class="kg-image" alt="welcome-to-your-vuejs-app" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/welcome-to-your-vuejs-app.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/03/welcome-to-your-vuejs-app.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/welcome-to-your-vuejs-app.png 1519w" sizes="(min-width: 1200px) 1200px" width="1519" height="866" loading="lazy"><figcaption>Tela de instalação padrão do Vue.js</figcaption></figure><p>Antes de prosseguir com a criação dos componentes reais que a nossa aplicação de <em>front-end</em> terá, vamos instalar a parte do <em>back-end</em> da nossa aplicação por meio da CLI do .NET Core.</p><h3 id="como-configurar-o-back-end">Como configurar o <em>back-end</em></h3><p>Como mencionado acima, usaremos outra ferramenta de linha de comando, a CLI do .NET Core, que possibilita a criação e configuração de apps .NET.</p><p>Se você ainda não tem, pode usar este<a href="https://dotnet.microsoft.com/download/dotnet-core/thank-you/sdk-3.1.401-windows-x64-installer"> link</a> para baixá-la e, em seguida, instalá-la. </p><p>Depois de ter a CLI do .NET Core instalada, vá para o diretório raiz do seu projeto e execute o seguinte comando para criar o <em>back-end </em>da nossa aplicação. Criaremos uma pasta chamada <code>backend</code> e instalaremos um app .NET para a web dentro dela:</p><pre><code>dotnet new web -o backend</code></pre><h3 id="gitignore-io"><strong><strong>gitignore.io</strong></strong></h3><p>Antes de continuar com a instalação dos próximos pacotes que precisaremos, vamos organizar nosso arquivo <em>.gitignore</em>.</p><p>Este é um arquivo de configuração que informa ao Git o que ignorar ao fazer o <em>commit</em> das alterações em repositórios baseados em Git (os do GitHub).</p><p>Como queremos ter um arquivo .gitignore, ele incluirá regras para dois tipos de aplicações:</p><ul><li>uma baseada em Node.js, que é o nosso <em>front-end</em> do Vue.js; e</li><li>uma para o .NET (C#) que é o nosso <em>back-end</em>.</li></ul><p>Para isso, usaremos uma ferramenta chamada gitignore.io. Essa ferramenta vai gerar esses arquivos para nós. A vantagem de usar essa ferramenta é que ela nos permite digitar quais são nossas linguagens de programação/plataformas e gera o arquivo .gitignore para nós.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-61.png" class="kg-image" alt="image-61" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-61.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/03/image-61.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-61.png 1065w" width="1065" height="552" loading="lazy"><figcaption>Usando o gitignore.io para gerar um arquivo .gitignore</figcaption></figure><p>Além disso, no topo do arquivo gerado, ele salva links para criação ou edição posterior, como mostrado abaixo:</p><pre><code># Created by https://www.toptal.com/developers/gitignore/api/webstorm,vue,vuejs,visualstudio
# Edit at https://www.toptal.com/developers/gitignore?templates=webstorm,vue,vuejs,visualstudio</code></pre><p>Agora, estamos prontos para instalar o restante dos pacotes que precisamos.</p><p>Primeiro, vamos instalar um pacote chamado SpaServices, que nos permitirá ter a aplicação em execução usando apenas um URL e apontando para a aplicação .NET. De sua parte, ele encaminhará solicitações para a nossa aplicação de <em>front-end</em>.</p><p>Para instalá-lo, abra o seu terminal, vá para a pasta <code>backend</code> do seu projeto e digite o seguinte comando:</p><pre><code class="language-bash">dotnet add package Microsoft.AspNetCore.SpaServices.Extensions --version 3.1.8
</code></pre><p>Depois disso, precisamos configurar a nossa aplicação de <em>back-end</em> com o pacote SpaServices para ter o resultado desejado.</p><p>Todas as solicitações serão encaminhadas para a nossa aplicação de <em>back-end</em> .NET e, se a solicitação for destinada ao <em>front-end</em>, ela será encaminhada.</p><p>Para fazer isso, abra o arquivo <a href="https://github.com/mihailgaberov/pizza-app/blob/master/backend/Startup.cs">Startup.cs</a> e atualize seu conteúdo para ficar assim:</p><pre><code class="language-c">using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

namespace backend
{
    public class Startup
    {
        public IConfiguration Configuration { get; }

        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        // Este método é chamado pelo tempo de execução. Use-o para adicionar serviços ao contêiner.
        // Para obter mais informações sobre como configurar sua aplicação, acesse https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            string connectionString = Configuration.GetConnectionString("DefaultConnection");
            services.AddDbContext&lt;ApplicationDbContext&gt;(options =&gt; options.UseSqlite(connectionString));
            services.AddSpaStaticFiles(configuration: options =&gt; { options.RootPath = "wwwroot"; });
            services.AddControllers();
            services.AddCors(options =&gt;
            {
                options.AddPolicy("VueCorsPolicy", builder =&gt;
                {
                    builder
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials()
                    .WithOrigins("https://localhost:5001");
                });
            });
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
  .AddJwtBearer(options =&gt;
                {
                    options.Authority = Configuration["Okta:Authority"];
                    options.Audience = "api://default";
                });
            services.AddMvc(option =&gt; option.EnableEndpointRouting = false);
        }

        // Este método é chamado pelo tempo de execução. Use-o para configurar o pipeline da solicitação HTTP.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ApplicationDbContext dbContext)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseCors("VueCorsPolicy");

            dbContext.Database.EnsureCreated();
            app.UseAuthentication();
            app.UseMvc();
            app.UseRouting();
            app.UseEndpoints(endpoints =&gt; { endpoints.MapControllers(); });
            app.UseSpaStaticFiles();
            app.UseSpa(configuration: builder =&gt;
            {
                if (env.IsDevelopment())
                {
                    builder.UseProxyToSpaDevelopmentServer("http://localhost:8080");
                }
            });
        }
    }
}</code></pre><p>Essa é a versão final do arquivo Startup.cs e, por isso, você provavelmente deve ter notado algumas outras coisas nela. Voltaremos nisso um pouco mais tarde neste tutorial.</p><p>Neste ponto, você deve ser capaz de executar a sua aplicação <em>back-end</em>. Se quiser fazer isso, execute os seguintes comandos a partir da pasta raiz do seu projeto:</p><pre><code>cd backend
dotnet run</code></pre><h2 id="como-configurar-a-autentica-o">Como configurar a autenticação</h2><p>Como você deve se lembrar da descrição no início, nossa aplicação deve ter uma opção de registro/login.</p><p>Para atender a esse requisito, usaremos um serviço terceirizado chamado Okta. Instalaremos os pacotes necessários para usar o Okta SDK no <em>front-end</em> e no <em>back-end</em> do nosso app.</p><p>Antes disso, porém, você precisa criar uma conta no site deles e obter acesso ao painel de administração. A partir daí, você pode criar uma aplicação. Aqui vemos como fica na minha aplicação:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-62.png" class="kg-image" alt="image-62" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-62.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/03/image-62.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-62.png 1511w" sizes="(min-width: 1200px) 1200px" width="1511" height="610" loading="lazy"></figure><p>Agora, vamos começar com o pacote que precisamos para nosso <em>front-end</em>. Na pasta raiz, execute os seguintes comandos:</p><pre><code class="language-bash">cd frontend
npm i @okta/okta-vue</code></pre><p>Após esta etapa, estamos prontos para alterar nossa aplicação do Vue.js para que use as vantagens do Okta SDK.</p><p>Também instalaremos outro pacote, chamado BootstrapVue, que fornece um conjunto de componentes do Vue.js bonitos e prontos para uso. Isso nos ajudará a economizar tempo de desenvolvimento e também nos dará um <em>front-end</em> de boa aparência.</p><p>Para instalá-lo, execute o seguinte na sua pasta <code>frontend</code>:</p><pre><code class="language-bash">npm i vue bootstrap-vue bootstrap</code></pre><h3 id="como-configurar-o-roteador">Como configurar o roteador</h3><p>Chegou a hora de escrever um pouco de código. Precisamos editar nosso <a href="https://router.vuejs.org/">roteador</a> para aplicar o que vem dos serviços de autenticação do Okta.</p><p>Você pode ver o arquivo completo no meu repositório do GitHub, mas aqui está a parte essencial que você precisa configurar com seus próprios dados (que você obteve quando se registrou no site do desenvolvedor do Okta):</p><pre><code class="language-javascript">Vue.use(Auth, {
  issuer: 'https://dev-914982.okta.com/oauth2/default',
  client_id: '0oatq53f87ByM08MQ4x6',
  redirect_uri: 'https://localhost:5001/implicit/callback',
  scope: 'openid profile email'
})

....

router.beforeEach(Vue.prototype.$auth.authRedirectGuard())</code></pre><h3 id="tela-inicial">Tela inicial</h3><p>Depois de classificar nosso roteador, podemos finalmente fazer algumas alterações na tela inicial da nossa aplicação, que ficará visível para nossos usuários.</p><p>Abra o arquivo <a href="https://github.com/mihailgaberov/pizza-app/blob/master/frontend/src/App.vue">App.vue</a> em seu IDE e altere seu conteúdo da seguinte maneira:</p><pre><code class="language-javascript">&lt;template&gt;
  &lt;div id="app"&gt;
    &lt;header&gt;
      &lt;b-navbar toggleable="md" type="light" variant="light"&gt;
        &lt;b-navbar-toggle target="nav-collapse"&gt;&lt;/b-navbar-toggle&gt;
        &lt;b-navbar-brand to="/"&gt;Love Pizza&lt;/b-navbar-brand&gt;
        &lt;b-collapse is-nav id="nav-collapse"&gt;
          &lt;b-navbar-nav&gt;
            &lt;b-nav-item href="#" @click.prevent="login" v-if="!user"&gt;Login&lt;/b-nav-item&gt;
            &lt;b-nav-item href="#" @click.prevent="logout" v-else&gt;Logout&lt;/b-nav-item&gt;
          &lt;/b-navbar-nav&gt;
        &lt;/b-collapse&gt;
      &lt;/b-navbar&gt;
    &lt;/header&gt;
    &lt;main&gt;
      &lt;div&gt;
        Love pizza button and clicks counter here
      &lt;/div&gt;
    &lt;/main&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  name: 'app',
  data() {
    return {
      user: null
    }
  },
  async created() {
    await this.refreshUser()
  },
  watch: {
    '$route': 'onRouteChange'
  },
  methods: {
    login() {
      this.$auth.loginRedirect()
    },
    async onRouteChange() {
      await this.refreshUser()
    },
    async refreshUser() {
      this.user = await this.$auth.getUser()
    },
    async logout() {
      await this.$auth.logout()
      await this.refreshUser()
      this.$router.push('/')
    }
  }
}
&lt;/script&gt;

&lt;style lang="scss"&gt;
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

#nav {
  padding: 30px;

  a {
    font-weight: bold;
    color: #2c3e50;

    &amp;.router-link-exact-active {
      color: #42b983;
    }
  }
}
&lt;/style&gt;</code></pre><p>Neste momento, sua aplicação deve ter a seguinte aparência:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-173.png" class="kg-image" alt="image-173" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-173.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-173.png 811w" width="811" height="525" loading="lazy"><figcaption><em>Front-end</em> do app em Vue.js – em desenvolvimento</figcaption></figure><p><strong>Observação</strong>: não se confunda com o texto 'Love pizza button and clicks counter here' (aqui vão o botão de pizza e o contador de cliques). Ao criar as UIs, é uma boa prática deixar esses espaços reservados para componentes que serão desenvolvidos no futuro.</p><p>No nosso caso, é aqui que adicionaremos os componentes responsáveis pelo botão 'I love it' e para o contador posteriormente. Eles mostrarão o número de votos por usuário.</p><figure class="kg-card kg-code-card"><pre><code class="language-javascript">&lt;main&gt;
  &lt;div&gt;
  	Love pizza button and clicks counter here
  &lt;/div&gt;
&lt;/main&gt;</code></pre><figcaption>Espaço reservado para componentes a serem adicionados posteriormente</figcaption></figure><h3 id="autentica-o-no-back-end">Autenticação no <em>back-end</em></h3><p>Até agora, configuramos nosso <em>front-end</em> para que use o serviço de autenticação fornecido pelo Okta. Porém, para ter toda a imagem pronta para uso, precisamos fazer o mesmo no lado do <em>back-end</em>.</p><p>É de onde faremos chamadas HTTP, para nos comunicarmos com o banco de dados. Como você verá mais adiante, algumas dessas chamadas precisarão ser autenticadas para serem bem-sucedidas.</p><p>Vamos começar novamente com a instalação de alguns pacotes que facilitarão nosso trabalho. No seu terminal, vá para o diretório <code>backend</code> e execute o seguinte:</p><pre><code class="language-bash">dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer --version 3.1.8
dotnet add package Microsoft.Extensions.Configuration --version 3.1.7</code></pre><p>Então, precisamos de outro pacote que nos ajude a configurar nosso banco de dados. Usaremos o banco de dados SQLite, que é superfácil de usar, na configuração do .NET Core.</p><p>Ainda na pasta <code>backend</code>, execute:</p><pre><code class="language-bash">dotnet add package Microsoft.EntityFrameworkCore.Sqlite --version 2.1.1</code></pre><p>Assim que terminarmos as instalações, certifique-se de que tem o conteúdo completo do arquivo <a href="https://github.com/mihailgaberov/pizza-app/blob/master/backend/Startup.cs">Startup.cs</a> (e se ainda não o fez, recomendo fazer isso agora).</p><h3 id="pizzavotesapiservice"><strong><strong>PizzaVotesApiService</strong></strong></h3><p>OK, pessoal! &nbsp;Configuramos nosso <em>front-end</em> e nosso <em>back-end</em> para oferecer suporte à autenticação. Adicionamos o SQLite como um banco de dados a ser usado para armazenar os votos dos usuários. Por fim, temos uma versão inicial da nossa tela inicial.</p><p>Agora, é hora de implementar um serviço no <em>front-end</em> que nos permitirá consumir a API do nosso <em>back-end</em>.</p><p>Ótimo trabalho até agora!</p><p>Antes de poder fazer chamadas HTTP do <em>front-end</em> para o <em>back-end</em>, precisamos instalar mais um pacote em nossa aplicação do Vue.js. Esse pacote se chama axios e nos dá a capacidade de fazer <a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest" rel="nofollow">XMLHttpRequests</a> a partir do navegador, que é exatamente o que precisamos.</p><p>Abra seu terminal, vá para a pasta <code>frontend</code> do seu projeto e execute:</p><pre><code>npm i axios</code></pre><p>Em seguida, em seu IDE, vá para a pasta <code>src</code> do <em>front-end </em>do seu app, crie um arquivo .js e adicione o seguinte código dentro dele:</p><pre><code>import Vue from 'vue'
import axios from 'axios'

const client = axios.create({
    baseURL: 'http://localhost:5000/api/pizzavotes',
    json: true
})

export default {
    async execute(method, resource, data) {
        const accessToken = await Vue.prototype.$auth.getAccessToken()
        return client({
            method,
            url: resource,
            data,
            headers: {
                Authorization: `Bearer ${accessToken}`
            }
        }).then(req =&gt; {
            return req.data
        })
    },
    getAll() {
        return this.execute('get', '/')
    },
    getById(id) {
        return this.execute('get', `/${id}`)
    },
    create(data) {
        return this.execute('post', '/', data)
    },
    update(id, data) {
        return this.execute('put', `/${id}`, data)
    },
}</code></pre><p>Eu dei nome ao meu arquivo de <a href="https://github.com/mihailgaberov/pizza-app/blob/master/frontend/src/PizzaVotesApiService.js">PizzaVotesApiService.js</a>. Pararemos com a integração da API por um tempo e criaremos outro componente que conterá os controles que os usuários usarão para interagir com essa API.</p><h3 id="componente-do-painel">Componente do painel</h3><p>Diga "olá" para o nosso componente <a href="https://github.com/mihailgaberov/pizza-app/blob/master/frontend/src/components/Dashboard.vue">Dashboard.vue</a>.</p><p>É aqui que colocaremos o botão 'I love it' ('Eu adoro pizza') e um pequeno contador de votos.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-63.png" class="kg-image" alt="image-63" width="207" height="183" loading="lazy"><figcaption>Botão 'I love it' e contador de votos</figcaption></figure><p>Também adicionaremos uma imagem de pizza divertida.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-64.png" class="kg-image" alt="image-64" width="250" height="284" loading="lazy"><figcaption>Imagem da pizza</figcaption></figure><p>Também adicionaremos um belo gráfico de barras, mostrando os X principais eleitores.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-65.png" class="kg-image" alt="image-65" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-65.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-65.png 641w" width="641" height="603" loading="lazy"><figcaption>Gráfico de barras dos principais votantes</figcaption></figure><p>Você pode copiar e colar o conteúdo completo do arquivo do meu repositório para que possamos continuar integrando tudo.</p><h3 id="integra-o-da-api">Integração da API</h3><p>Vou usar um pequeno diagrama para representar o fluxo de dados. Como dizem, "uma imagem vale mais que mil palavras":</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/data-flow.png" class="kg-image" alt="data-flow" width="571" height="61" loading="lazy"><figcaption>Diagrama do fluxo de dados</figcaption></figure><p>Como você pode ver no diagrama (eu espero), quando o usuário insere seus votos, os dados vão do componente do painel para o serviço de API que criamos para comunicação com a API de <em>back-end</em>. Em seguida, ele alcança o controlador de <em>back-end</em> que está de fato fazendo as chamadas HTTP.</p><p>Depois que os dados são buscados, o serviço os repassa para nossa interface do usuário, onde os mostramos por meio de nossos componentes do Vue.js. Como você verá, existe alguma lógica adicional que verifica se o usuário está autenticado para saber quais chamadas executar.</p><p>Aqui está a implementação do <a href="https://github.com/mihailgaberov/pizza-app/blob/master/backend/PizzaVotesController.cs"><em>controller</em></a> em si:</p><pre><code class="language-c">using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace backend.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class PizzaVotesController : ControllerBase
    {
        private readonly ApplicationDbContext _dbContext;

        public PizzaVotesController(ApplicationDbContext dbContext)
        {
            _dbContext = dbContext;
        }

        // GET api/pizzavotes
        [HttpGet]
        public async Task&lt;ActionResult&lt;List&lt;PizzaVotes&gt;&gt;&gt; Get()
        {
            return await _dbContext.PizzaVotes.ToListAsync();
        }

        // GET api/pizzavotes/{email}
        [Authorize]
        [HttpGet("{id}")]
        public async Task&lt;ActionResult&lt;PizzaVotes&gt;&gt; Get(string id)
        {
            return await _dbContext.PizzaVotes.FindAsync(id);
        }

        // POST api/pizzavotes
        [Authorize]
        [HttpPost]
        public async Task Post(PizzaVotes model)
        {
            await _dbContext.AddAsync(model);
            await _dbContext.SaveChangesAsync();
        }

        // PUT api/pizzavotes/{email}
        [Authorize]
        [HttpPut("{id}")]
        public async Task&lt;ActionResult&gt; Put(string id, PizzaVotes model)
        {
            var exists = await _dbContext.PizzaVotes.AnyAsync(f =&gt; f.Id == id);
            if (!exists)
            {
                return NotFound();
            }

            _dbContext.PizzaVotes.Update(model);

            await _dbContext.SaveChangesAsync();

            return Ok();
        }
    }
}</code></pre><p>Aqui temos quatro métodos para executar as quatro operações básicas:</p><ul><li>Obter todos os registros do banco de dados;</li><li>Obter os registros de um usuário (pelo endereço de e-mail);</li><li>Criar um novo registro de usuário;</li><li>Atualizar os registros de um usuário existente.</li></ul><p>Você provavelmente notou a cláusula <code>[Authorize]</code> acima de três dos quatro métodos. Esses métodos vão exigir que o usuário seja autenticado para executar.</p><p>Deixaremos o método <code>GET api/pizzavotes</code> sem autorização para obter todos os registros de propósito. Como gostaríamos de mostrar o gráfico de barras na tela inicial para todos os usuários, precisaremos poder fazer esta chamada, independentemente de o usuário estar autenticado ou não.</p><h3 id="permitindo-o-registro">Permitindo o registro</h3><p>Algo para se observar: se você gostaria de ter um 'Cadastre-se' em sua tela de login, você precisa permitir isso no painel de administração do Okta.</p><p>Uma vez logado, selecione no menu <strong><em>Users -&gt; Registration </em></strong>(Usuários -&gt; Registro):</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-66.png" class="kg-image" alt="image-66" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-66.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/03/image-66.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-66.png 1080w" width="1080" height="534" loading="lazy"><figcaption>Permitir registro de novos usuários</figcaption></figure><h3 id="finalizando-o-back-end"><strong>Finalizando o<strong> </strong><em><strong>back</strong>-<strong>end</strong></em></strong></h3><p>Para que o <em>back-end</em> de sua aplicação funcione totalmente, dê uma olhada no meu <a href="https://github.com/mihailgaberov/pizza-app/tree/master/backend">repositório aqui </a>e adicione os arquivos ausentes.</p><p>Se você acompanhou até este ponto, você deve ter os seguintes arquivos (exceto a pasta de teste, pois vamos adicioná-la mais a frente):</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-67.png" class="kg-image" alt="image-67" width="354" height="484" loading="lazy"><figcaption>Estrutura do <em>back-end</em> do app</figcaption></figure><h3 id="finalizando-o-front-end"><strong>Finalizando o <strong><em>front</em></strong><em>-</em><strong><em>end</em></strong></strong></h3><p>Para finalizar o trabalho do <em>front-end</em> da nossa aplicação, criaremos mais dois componentes.<br><br>O primeiro renderizará o gráfico de barras mencionado acima, enquanto o segundo exibirá o endereço de e-mail do usuário que está conectado no momento.</p><p>No seu IDE, vá para <code>frontend/src/components</code> e crie dois arquivos, chamados <a href="https://github.com/mihailgaberov/pizza-app/blob/master/frontend/src/components/Username.vue">Username.vue</a> e <a href="https://github.com/mihailgaberov/pizza-app/blob/master/frontend/src/components/VotesChart.vue">VotesChart.vue</a>, respectivamente.</p><p>Username.vue é um componente muito curto e simples que pega o endereço de e-mail do usuário como suporte e o renderiza. Aqui está a sua implementação:</p><pre><code>&lt;template&gt;
  &lt;div class="username"&gt;{{ username }}&lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  props: { username: String },
}
&lt;/script&gt;

&lt;style lang="scss"&gt;
.username {
  color: rebeccapurple;
  display: flex;
  align-items: center;
  justify-content: center;
}

.username::before {
  content: "•";
}

.username::after {
  content: "•";
}
&lt;/style&gt;
</code></pre><p>Um único ponto que é preciso observar aqui é que estamos usando SASS/SCSS para definir os estilos dos componentes. Isso é possível por termos escolhido essa opção no início (quando estávamos instalando nossa aplicação do Vue.js).</p><p>Para desenhar o gráfico, usaremos um pacote chamado vue-chart.js. Instale-o executando o seguinte comando na sua pasta <code>frontend</code>:</p><pre><code>npm i vue-chartjs chart.js</code></pre><p>Nosso componente <strong>VotesChart.vue</strong> será uma espécie de <em>wrapper</em> para o componente gráfico de barras que vem do pacote vue-chartjs.</p><p><br>Nós o usamos para obter os dados do componente pai, <strong>Dashboard.vue</strong>, e processá-los. Classificamos o array de dados para exibir nossos principais votantes, classificados do maior para o menor número de votos. </p><p>Em seguida, passamos para o componente do gráfico de barras para visualizá-lo. Aqui está a implementação completa:</p><pre><code>&lt;script&gt;
import { Bar } from 'vue-chartjs'

const TOP_N_VOTERS_TO_SHOW_ON_CHART = 10

// Usado para ordenar pelo valor dos votos - do maior para o menor (desc)
function sortByStartDate(nextUser, currentUser) {
  const nextVoteValue = nextUser.value
  const currentVoteValue = currentUser.value
  return currentVoteValue - nextVoteValue
}

export default {
  extends: Bar,
  props: { data: Array },

  watch: {
    data: async function (newVal) {
      const sortedVotes = Array.from(newVal).sort(sortByStartDate).slice(0, TOP_N_VOTERS_TO_SHOW_ON_CHART)
      this.labels = sortedVotes.map(user =&gt; user.id)
      this.values = sortedVotes.map(user =&gt; user.value)

      this.renderChart({
        labels: this.labels,
        datasets: [
          {
            label: 'Pizza Lovers',
            backgroundColor: '#f87979',
            data: this.values,
          }
        ]
      }, {
        scales: {
          yAxes: [{
            ticks: {
              stepSize: 1,
              min: 0,
              max: this.values[0]
            }
          }]
        }
      })
    }
  }
}
&lt;/script&gt;
</code></pre><p>Observe que há uma constante na parte superior do arquivo que definirá quantos dos principais votantes gostaríamos de mostrar neste gráfico. Atualmente, está definida como 10, mas você pode alterá-la como quiser.</p><p><br>Quando estiver pronto com todo o <em>front-end</em> e quiser executar a aplicação, você pode fazer isso:</p><p>Vá para a pasta <code>frontend</code> e execute:</p><pre><code class="language-bash">npm run serve</code></pre><p>Vá para a pasta <code>backend</code> e execute:</p><pre><code class="language-bash">dotnet run</code></pre><p>Abra seu navegador e acesse <a href="https://localhost:5001">https://localhost:5001</a>.</p><h2 id="como-testar-nossas-aplica-es">Como testar nossas aplicações</h2><p>Até agora, criamos uma aplicação de página única moderna e totalmente funcional com um <em>back-end</em> em .NET Core e um banco de dados SQLite. Isso é muito trabalho. Parabéns! ✨</p><p>Facilmente, poderíamos parar aqui e tomar um suco ou um café.</p><p>Poré,...<br><br>Somos razoáveis o suficiente para saber que, se não testarmos nossas aplicações, não podemos garantir que funcionarão conforme o esperado.</p><p>Também sabemos que, se quisermos tornar nosso código testável, devemos escrevê-lo de maneira bem estruturada, tendo em mente <a href="https://www.dotnettricks.com/learn/designpatterns/different-types-of-software-design-principles">os princípios básicos do design de software</a> (texto em inglês).</p><p>Espero ter convencido você a continuar trabalhando neste tutorial. Afinal, a única coisa que nos resta fazer é escrever alguns testes para nossas duas aplicações. Então, vamos fazê-lo!</p><p>Trataremos do funcionamento de nossa API de <em>back-end</em> com<strong> testes de integração</strong> e, em nosso <em>front-end</em>, escreveremos testes de <strong>unidade</strong> e <strong>integração</strong>.</p><h3 id="testes-de-unidade-e-de-integra-o">Testes de unidade e de integração</h3><p>Antes de passar para o código, gostaria de dizer algumas palavras sobre esses tipos de testes e responder a algumas das perguntas mais frequentes.</p><p>Você deve estar se perguntando, o que são testes de unidade? O que são testes de integração? Por que nós precisamos deles? Quando devemos usar cada um deles?</p><p>Partindo da primeira pergunta, um<strong> teste de unidade</strong> é um trecho de código que testa a funcionalidade de um módulo encapsulado (ou seja, outro trecho). É escrito como uma função ou algum tipo de bloco de código independente.</p><p>Eles são bons de se ter, porque fornecem um feedback rápido do tempo de desenvolvimento e mantêm o código protegido contra regressões quando novos recursos são adicionados.</p><p>Os <strong>testes de integração</strong> são úteis quando precisamos testar como vários módulos/unidades estão trabalhando juntos. Por exemplo, uma API REST e uma interação com um banco de dados.</p><p>Dependendo do tamanho da aplicação em que estamos trabalhando, podemos precisar apenas de testes de integração. Às vezes, no entanto, precisamos de testes de integração e de unidade para testar de verdade o nosso código.</p><p>Idealmente, deveríamos ter ambos, pois são partes essenciais da pirâmide de testes e são os mais baratos de implementar.</p><p>Em alguns casos, contudo, como para nosso <em>back-end</em>, apenas testes de integração são necessários para cobrir a funcionalidade que vale a pena ser testada. Temos apenas os métodos de API para trabalhar com o banco de dados.</p><h3 id="como-criar-nossos-testes-de-back-end">Como criar nossos testes de <em>back-end</em></h3><p>Desta vez, começaremos criando nossa solução de teste. Para fazer isso, você precisa fazer algumas coisas.<br><br>Primeiro, instale a biblioteca xUnit executando o seguinte no diretório raiz do projeto:</p><pre><code class="language-bash">dotnet add package xUnit</code></pre><p>Em seguida, vá para a pasta de <code>backend</code> e crie e esvazie a pasta chamada <code>tests</code>. Então, dentro dessa pasta, execute: </p><pre><code class="language-bash">dotnet new xunit -o PizzaVotes.Tests</code></pre><p>Feito isso, abra backend.csproj e adicione as duas linhas a seguir ao bloco <code>&lt;PropertyGroup&gt;</code>:</p><pre><code>&lt;GenerateAssemblyInfo&gt;false&lt;/GenerateAssemblyInfo&gt;
&lt;GenerateTargetFrameworkAttribute&gt;false&lt;/GenerateTargetFrameworkAttribute&gt;</code></pre><p>Em seguida, vá para a pasta <code>tests</code> e instale os seguintes pacotes: </p><pre><code>Microsoft.AspNetCore.Mvc
Microsoft.AspNetCore.Mvc.Core
Microsoft.AspNetCore.Diagnostics
Microsoft.AspNetCore.TestHost
Microsoft.Extensions.Configuration.Json
Microsoft.AspNetCore.Mvc.Testing</code></pre><p>Você faz isso executando cada um dos seguintes comandos em seu terminal:</p><pre><code class="language-bash">dotnet add package Microsoft.AspNetCore.Mvc --version 2.2.0
dotnet add package Microsoft.AspNetCore.Mvc.Core --version 2.2.5
dotnet add package Microsoft.AspNetCore.Diagnostics --version 2.2.0
dotnet add package Microsoft.AspNetCore.TestHost --version 3.1.8
dotnet add package Microsoft.AspNetCore.Mvc.Testing --version 3.1.8</code></pre><p>Depois de ter tudo instalado, estamos prontos para começar a escrever alguns testes.<br><br>Como você pode ver aqui, excetuando os próprios testes, adicionei mais dois arquivos que precisamos ou que são bons de se ter ao executar os testes.</p><p>Um deles é apenas um <a href="https://github.com/mihailgaberov/pizza-app/blob/master/backend/tests/PizzaVotes.Tests/ContentHelper.cs">arquivo auxiliar</a> com um método para lidar com objetos serializados e obter o conteúdo da string. O outro é o arquivo <a href="https://github.com/mihailgaberov/pizza-app/blob/master/backend/tests/PizzaVotes.Tests/TestFixture.cs">fixture</a>, onde temos as configurações e definições do nosso servidor de teste e o <em>client</em>.</p><p>Claro, há também um <a href="https://github.com/mihailgaberov/pizza-app/blob/master/backend/tests/PizzaVotes.Tests/PizzaVotesTests.cs">arquivo</a> com nossos testes. </p><p>Não vou colar o conteúdo desses arquivos aqui, pois este tutorial já ficou longo o suficiente.</p><p><strong>Você pode simplesmente copiá-los do meu repositório.</strong></p><p>Se você observar os testes mais de perto, poderá perceber que estamos testando apenas a primeira chamada, não autenticada, para uma resposta de sucesso. Para o restante, estamos verificando apenas a resposta HTTP 401, <code>Unauthorized</code> (não autorizada).</p><p>Isso ocorre porque apenas o primeiro método é público, ou seja, não precisa de autenticação.</p><p>Se tivéssemos os mesmos testes para todos os métodos, precisaríamos implementar um middleware apenas para autorizar nossa aplicação de teste na frente dos serviços de autenticação da Okta.</p><p>Como o objetivo deste tutorial é aprender uma variedade de coisas, podemos dizer que não vale a pena.</p><p>Agora a parte divertida: como executar os testes. Acontece que é muito simples. Basta ir ao seu diretório <code>tests</code> (onde está o arquivo tests.sln) do seu terminal e executar: &nbsp;</p><pre><code class="language-bash">dotnet test</code></pre><p>Você deve ver algo assim em seu terminal (ignore os avisos amarelos):</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-68.png" class="kg-image" alt="image-68" width="443" height="357" loading="lazy"><figcaption>Executando os testes do <em>back-end</em></figcaption></figure><h3 id="como-criar-nossos-testes-para-o-front-end">Como criar nossos testes para o <em>front-end</em></h3><p>É hora de adicionar alguns testes ao nosso <em>front-end</em>. Aqui, faremos testes de unidade e de integração.</p><p><strong>Testes de unidade</strong><br>Como mencionei acima, os testes de unidade são adequados quando temos um módulo ou componente que não possui dependências do mundo externo.</p><p>Esses componentes acabam sendo nossos componentes Username.vue e VotesChart.vue.</p><p>Eles são componentes representacionais, que recebem os dados de que precisam para funcionar adequadamente por meio de props. Isso significa que podemos escrever nossos testes da mesma maneira: passar a eles os dados de que precisam e verificar se os resultados de sua execução são os esperados.</p><p>Aqui, há algo importante para se destacar. Isso não significa que aquilo que foi fornecido pelo pacote <strong>@vue/test-utils</strong> (que vem ao instalar o Vue.js) não tenha sido o suficiente para testar ambos os componentes.</p><p>Em vez disso, para fins educacionais, decidi instalar e usar a biblioteca de testes do Vue também. É por isso que um dos componentes abaixo é testado com @vue/test-utils, mas o outro é testado com @testing-library/vue.</p><p>Não se esqueça de instalá-la antes de executar o teste:</p><pre><code>npm i --save-dev @testing-library/vue</code></pre><p>Novamente, para economizar espaço, não vou colar o código do teste do componente aqui, mas você pode vê-lo facilmente <a href="https://github.com/mihailgaberov/pizza-app/blob/master/frontend/tests/unit/Username.spec.js">aqui</a> e <a href="https://github.com/mihailgaberov/pizza-app/blob/master/frontend/tests/unit/VotesChart.spec.js">aqui</a>. </p><p>Então, para executar os testes de unidade do seu <em>front-end</em>, vá para a pasta <code>frontend</code> e execute: </p><pre><code>npm run test:unit</code></pre><p><strong>Teste de integração</strong><br>Esse tema é provavelmente bem interessante para alguns de vocês.</p><p>Se você se lembra do início deste tutorial, quando instalamos nossa aplicação do Vue.js, para nossa solução de testes e2e (ou de integração), selecionamos o <a href="https://www.cypress.io/">Cypress.js</a>.</p><p>Esta é uma ferramenta superfácil de usar, que permite aos desenvolvedores escrever testes e2e (end-to-end, ou de ponta a ponta) reais para suas aplicações, fornecendo feedback imediato.</p><p>Por experiência pessoal, eu diria que trabalhar com o Cypress é mais prazeroso do que com outros frameworks semelhantes. Se você tiver experiência anterior com estruturas como Nightwatch.js ou Selenium, o que você vê abaixo pode ser familiar para você.</p><p>Antes de executar nossos testes com o Cypress, precisamos fazer algumas pequenas alterações em sua configuração.</p><p>Encontre o <a href="https://github.com/mihailgaberov/pizza-app/blob/master/frontend/tests/e2e/plugins/index.js">arquivo de índice</a> <code>plugins</code> e adicione a seguinte linha à declaração de retorno no final do arquivo:</p><pre><code>  baseUrl: "https://localhost:5001"</code></pre><p>Agora, atualize o conteúdo do test.js na pasta <code>specs</code> conforme mos<em>t</em>rado <a href="https://github.com/mihailgaberov/pizza-app/blob/master/frontend/tests/e2e/specs/test.js">aqui</a>.</p><p>Depois de fazer tudo, você poderá executar seus testes e2e via Cypress. Você pode fazer isso executando o seguinte comando enquanto estiver no diretório do <code>frontend</code>:</p><pre><code>npm run test:e2e</code></pre><p>⚡Não se esqueça de iniciar sua aplicação de <em>back-end</em> antes de executar os testes e2e para que funcionem corretamente.</p><p>Se você fez tudo como mostramos, depois de executar o comando acima, você deve ver algo assim em seu terminal:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-69.png" class="kg-image" alt="image-69" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-69.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-69.png 640w" width="640" height="223" loading="lazy"><figcaption>Executando testes e2e</figcaption></figure><p>Uma nova janela do navegador será aberta pelo próprio Cypress.js, onde você pode usar o URI fornecido para ver e executar seus testes.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-70.png" class="kg-image" alt="image-70" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-70.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/03/image-70.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-70.png 1174w" width="1174" height="806" loading="lazy"><figcaption>UI do Cypress.js</figcaption></figure><p>Quando todos os testes forem aprovados, você deverá ver uma tela como esta:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-71.png" class="kg-image" alt="image-71" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-71.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/03/image-71.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1600/2023/03/image-71.png 1600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-71.png 1912w" sizes="(min-width: 1200px) 1200px" width="1912" height="1122" loading="lazy"><figcaption>Os testes e2e passaram com sucesso</figcaption></figure><h2 id="conclus-o"><strong><strong>Conclu</strong>são</strong></h2><p>Neste tutorial, vimos como usar duas das tecnologias mais importantes do mercado para criar um <em>front-end</em> e um <em>back-end</em>.</p><p>Também aprendemos como combiná-las adequadamente para criar uma aplicação de página única pequena, mas totalmente funcional, com suporte a banco de dados.</p><p>Por fim, também escrevemos testes de unidade e de integração para ambas as pontas do projeto.</p><p>Acredito que esse tipo de exercício seja benéfico tanto para leitores experientes quanto para iniciantes, pois aborda muitas coisas diferentes passo a passo. No final, se tiver concluído todo o processo, você tem uma aplicação funcional de exemplo.</p><p>Este tutorial acabou sendo muito mais longo do que eu inicialmente pensei que seria. Se, contudo, você já fez tudo, eu admiro você! Espero que tenha sido um prazer para você ler o artigo, assim como foi para mim escrevê-lo.</p><p>Obrigado pela leitura!</p><h2 id="recursos"><strong><strong>Re</strong>cursos</strong></h2><p>Você pode encontrar abaixo os links que foram úteis para mim, de algum modo, enquanto escrevia o artigo (recursos em inglês).</p><p><a href="https://consultwithgriff.com/spas-with-vuejs-aspnetcore/">https://consultwithgriff.com/spas-with-vuejs-aspnetcore/</a><br><a href="https://github.com/okta/okta-auth-dotnet">https://github.com/okta/okta-auth-dotnet</a><br><a href="https://docs.microsoft.com/en-us/dotnet/core/testing/unit-testing-with-dotnet-test">https://docs.microsoft.com/en-us/dotnet/core/testing/unit-testing-with-dotnet-test</a><br><a href="https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpresponsemessage?view=netcore-3.1">https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpresponsemessage?view=netcore-3.1</a><br><a href="https://vue-test-utils.vuejs.org/guides/#testing-key-mouse-and-other-dom-events">https://vue-test-utils.vuejs.org/guides/#testing-key-mouse-and-other-dom-events</a><br><a href="https://docs.cypress.io/guides/references/configuration.html#Options">https://docs.cypress.io/guides/references/configuration.html#Options</a><br><a href="https://docs.cypress.io/guides/tooling/visual-testing.html#Functional-vs-visual-testing">https://docs.cypress.io/guides/tooling/visual-testing.html#Functional-vs-visual-testing</a><br><a href="https://www.codingame.com/playgrounds/35462/creating-web-api-in-asp-net-core-2-0/part-3---integration-tests">https://www.codingame.com/playgrounds/35462/creating-web-api-in-asp-net-core-2-0/part-3---integration-tests</a><br><a href="https://testing-library.com/docs/vue-testing-library/intro">https://testing-library.com/docs/vue-testing-library/intro</a><br><a href="https://www.valentinog.com/blog/canvas/">https://www.valentinog.com/blog/canvas/</a></p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
