<?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: Thiago Rodrigues</title>
    <description>The latest articles on DEV Community by Thiago Rodrigues (@thethiago27).</description>
    <link>https://dev.to/thethiago27</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%2F502612%2Fd234f91b-61b8-452e-9680-6e62afb14282.jpeg</url>
      <title>DEV Community: Thiago Rodrigues</title>
      <link>https://dev.to/thethiago27</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thethiago27"/>
    <language>en</language>
    <item>
      <title>Criando um serviço de processamento de arquivos na AWS</title>
      <dc:creator>Thiago Rodrigues</dc:creator>
      <pubDate>Sat, 04 May 2024 02:08:00 +0000</pubDate>
      <link>https://dev.to/thethiago27/criando-um-servico-de-processamento-de-arquivos-na-aws-g37</link>
      <guid>https://dev.to/thethiago27/criando-um-servico-de-processamento-de-arquivos-na-aws-g37</guid>
      <description>&lt;p&gt;Hoje vamos estudar um caso sobre uma empresa que está enfrentando sérios problemas com sua infraestrutura atual para processar arquivos largos de CSV.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O problema:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;"Olá, somos a empresa Marcão Soldas, especializada em soldas e esquadrias.&lt;/p&gt;

&lt;p&gt;Atualmente, nosso setor financeiro utiliza planilhas do Excel para gerenciar as folhas de pagamento de funcionários, prestadores de serviços e contas a pagar.&lt;/p&gt;

&lt;p&gt;Nossa equipe está habituada ao Excel e não deseja migrar para outro sistema devido a algumas comodidades oferecidas pelas planilhas.&lt;/p&gt;

&lt;p&gt;No entanto, percebemos que, devido ao aumento no número de funcionários, as rotinas de pagamento estão se tornando longas e cansativas, podendo levar até 2 dias para concluirmos todos os pagamentos. Isso resulta em alguns funcionários recebendo antes que outros, causando insatisfação.&lt;/p&gt;

&lt;p&gt;Precisamos de um sistema onde possamos enviar nossa planilha do Excel com o valor que cada funcionário deve receber, juntamente com sua chave PIX, para realizar os pagamentos automaticamente.&lt;/p&gt;

&lt;p&gt;Não queremos gerenciar nenhum aspecto da aplicação, seja em nuvem ou na tecnologia escolhida. Vocês estão livres para escolher a melhor opção, mas não queremos gastar muito com custos de nuvem."&lt;/p&gt;

&lt;p&gt;Após ler esse grande problema da Marcão Soldas, temos alguns pontos para resolver:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Criar um sistema que possibilite o envio de planilhas.&lt;/li&gt;
&lt;li&gt;Um sistema que gerencie pagamentos e um gateway de pagamentos que possa realizar PIX.&lt;/li&gt;
&lt;li&gt;Precisamos nos atentar aos custos que essa aplicação terá, já que nosso cliente não quer gastar muito.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bom, tendo em vista todos esses requisitos, vamos parar para analisar alguns serviços de computação em nuvem da AWS.&lt;/p&gt;

&lt;p&gt;Temos o EC2 e o Lambda. Porém, não queremos ter o trabalho de ficar orquestrando contêineres ou usar o Kubernetes para isso. Do outro lado, temos o Lambda, que executa pequenas funções em máquinas dedicadas e são auto-gerenciáveis, ou seja, não precisamos nos preocupar com infraestrutura ou escalabilidade.&lt;/p&gt;

&lt;p&gt;Vamos usar também o API Gateway para receber o arquivo e salvá-lo em nosso bucket S3. Além disso, vamos utilizar o serviço de fila SQS para gerenciar os arquivos a serem processados e o SNS para ser um mensageiro quando precisarmos fazer um pagamento.&lt;/p&gt;

&lt;p&gt;Então, nossa infraestrutura ficaria assim:&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%2Fmb0jzohch2qvvc7ukwc8.jpg" 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%2Fmb0jzohch2qvvc7ukwc8.jpg" alt="Image description" width="719" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vamos entender o que está acontecendo acima:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Nosso cliente envia seu arquivo para uma rota em nosso API Gateway, que salva esse arquivo em um bucket S3.&lt;/li&gt;
&lt;li&gt;O Lambda recebe a notificação da criação desse arquivo e salva no DynamoDB algumas informações do arquivo, para servir como uma espécie de log.&lt;/li&gt;
&lt;li&gt;Via DynamoDB Stream, enviamos uma notificação para outro Lambda, que será responsável por notificar nosso SQS para gerenciar uma fila de processamento de arquivos.&lt;/li&gt;
&lt;li&gt;Nossa Lambda processa linha por linha do arquivo e captura as informações do recebedor, criando um tópico no SNS.&lt;/li&gt;
&lt;li&gt;O SNS recebe a notificação e a envia para o Lambda responsável por criar a solicitação de pagamento no gateway.&lt;/li&gt;
&lt;/ol&gt;

</description>
    </item>
    <item>
      <title>Criando um cassino com AWS: Criando um ambiente de CI/CD</title>
      <dc:creator>Thiago Rodrigues</dc:creator>
      <pubDate>Tue, 09 Apr 2024 20:10:50 +0000</pubDate>
      <link>https://dev.to/thethiago27/criando-um-cassino-com-aws-criando-um-ambiente-de-cicd-4ia0</link>
      <guid>https://dev.to/thethiago27/criando-um-cassino-com-aws-criando-um-ambiente-de-cicd-4ia0</guid>
      <description>&lt;p&gt;Seja bem-vindo à nossa primeira etapa sobre como criar um cassino com a Amazon AWS. Ao final desta série, você aprenderá a utilizar serviços da AWS como Lambda, API Gateway, IAM, SNS e DynamoDB.&lt;/p&gt;

&lt;p&gt;Iremos construir um cassino totalmente serverless, utilizando Lambda e API Gateway para gerenciar todas as nossas funções.&lt;/p&gt;

&lt;p&gt;No próximo post, exploraremos um pouco mais sobre esse universo serverless. Mas, nesse primeiro momento, iremos aprender a configurar nosso ambiente de deploy, pois ele será inteiramente responsável por automatizar as coisas nos bastidores.&lt;/p&gt;

&lt;p&gt;Para esta série de conteúdos, você precisará de:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uma conta no Github&lt;/li&gt;
&lt;li&gt;Uma conta na AWS&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configurando nosso ambiente de CI/CD
&lt;/h2&gt;

&lt;p&gt;Vamos começar do princípio. Nosso ambiente de CI/CD é crucial para este tutorial, pois, como utilizaremos serverless para nossas funções, poderíamos ter uma carga muito pesada de funções para fazer deploy manualmente. Imagine ter que fazer uma por uma manualmente? Seria um trabalhão. Por isso, iremos configurar um ambiente de pipeline com as seguintes etapas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Encontrar os nomes das funções dentro da pasta &lt;code&gt;lambda_functions&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Configurar nosso ambiente de desenvolvimento com Python 3.9.&lt;/li&gt;
&lt;li&gt;Instalar todas as dependências individuais de cada projeto.&lt;/li&gt;
&lt;li&gt;Compactar e atualizar as funções Lambda.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Segue a estrutura do projeto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- .github/workflows/deploy.yml&lt;/span&gt;
&lt;span class="c1"&gt;-- lambda_functions&lt;/span&gt;
   &lt;span class="c1"&gt;-- lambda_function_1&lt;/span&gt;
   &lt;span class="c1"&gt;-- lambda_function_2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dentro da nossa pasta .github/workflows, iremos criar um arquivo chamado deploy.yml e colar o código abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update Function Code&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;get-filenames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;lambdaArray&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.lambda_functions.outputs.lambdas }}&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get functions filenames&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lambda_functions&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;directories=$(tree lambda_functions -d -L 1 -J | jq -j -c '.[0].contents | map(.name)')&lt;/span&gt;
          &lt;span class="s"&gt;echo ::set-output name=lambdas::${directories}&lt;/span&gt;

  &lt;span class="na"&gt;update-code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;get-filenames&lt;/span&gt;
    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;lambda&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ fromJson(needs.get-filenames.outputs.lambdaArray) }}&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Python&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v5&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.9'&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pip'&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Zip And Install Lambda functions&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;cd lambda_functions/${{matrix.lambda}}&lt;/span&gt;
          &lt;span class="s"&gt;pip install -r requirements.txt -t .&lt;/span&gt;
          &lt;span class="s"&gt;zip -r ${{matrix.lambda}}.zip .&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up AWS Credentials&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;aws-access-key-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ACCESS_KEY_ID }}&lt;/span&gt;
          &lt;span class="na"&gt;aws-secret-access-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_SECRET_ACCESS_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update Lambdas code&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws lambda update-function-code --function-name=${{matrix.lambda}} --zip-file=fileb://lambda_functions/${{matrix.lambda}}/${{matrix.lambda}}.zip&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ACCESS_KEY_ID }}&lt;/span&gt;
          &lt;span class="na"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_SECRET_ACCESS_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;AWS_REGION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O código YAML acima define um fluxo de trabalho (workflow) para automação de deploys usando o GitHub Actions. Ele consiste em duas etapas principais:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;get-filenames&lt;/strong&gt;: Esta etapa é responsável por encontrar os nomes das funções dentro da pasta &lt;code&gt;lambda_functions&lt;/code&gt;. Utiliza a ferramenta &lt;code&gt;tree&lt;/code&gt; para listar os diretórios e arquivos dentro de &lt;code&gt;lambda_functions&lt;/code&gt;, em seguida usa &lt;code&gt;jq&lt;/code&gt; para filtrar apenas os nomes das funções e armazená-los como saída para uso posterior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;update-code&lt;/strong&gt;: Esta etapa depende da saída da etapa anterior e utiliza uma matriz para iterar sobre cada função encontrada. Para cada função, ela realiza as seguintes tarefas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configura o ambiente Python.&lt;/li&gt;
&lt;li&gt;Instala as dependências de cada função.&lt;/li&gt;
&lt;li&gt;Compacta o código da função em um arquivo &lt;code&gt;.zip&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Configura as credenciais da AWS.&lt;/li&gt;
&lt;li&gt;Atualiza o código da função Lambda na AWS com o arquivo compactado.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Este fluxo de trabalho automatiza o processo de atualização do código das funções Lambda sempre que ocorrer um push para a branch &lt;code&gt;master&lt;/code&gt; do repositório.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando uma chave secreta na AWS
&lt;/h2&gt;

&lt;p&gt;O código YAML acima define um fluxo de trabalho (workflow) para automação de deploys usando o GitHub Actions. Ele consiste em duas etapas principais:&lt;/p&gt;

&lt;p&gt;get-filenames: Esta etapa é responsável por encontrar os nomes das funções dentro da pasta lambda_functions. Utiliza a ferramenta tree para listar os diretórios e arquivos dentro de lambda_functions, em seguida usa jq para filtrar apenas os nomes das funções e armazená-los como saída para uso posterior.&lt;/p&gt;

&lt;p&gt;update-code: Esta etapa depende da saída da etapa anterior e utiliza uma matriz para iterar sobre cada função encontrada. Para cada função, ela realiza as seguintes tarefas:&lt;/p&gt;

&lt;p&gt;Configura o ambiente Python.&lt;br&gt;
Instala as dependências de cada função.&lt;br&gt;
Compacta o código da função em um arquivo .zip.&lt;br&gt;
Configura as credenciais da AWS.&lt;br&gt;
Atualiza o código da função Lambda na AWS com o arquivo compactado.&lt;br&gt;
Este fluxo de trabalho automatiza o processo de atualização do código das funções Lambda sempre que ocorrer um push para a branch master do repositório.&lt;/p&gt;

&lt;p&gt;IAM, ou Identity and Access Management (Gerenciamento de Identidade e Acesso), é um serviço da AWS que permite controlar o acesso aos recursos da AWS de forma segura. Com o IAM, você pode gerenciar usuários, grupos e permissões para conceder acesso apenas às ações necessárias dentro da sua conta AWS.&lt;/p&gt;

&lt;p&gt;No contexto deste tutorial, ao criar uma chave secreta na AWS, estamos configurando as credenciais de acesso que serão usadas pelo GitHub Actions para interagir com os serviços da AWS, como Lambda. Essas credenciais são essenciais para garantir que o processo de deploy automatizado tenha permissão para atualizar o código das funções Lambda na sua conta AWS.&lt;/p&gt;

&lt;p&gt;1-  Na barra de pesquisa procure por IAM&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%2F441d6er59fl0dszh16kf.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%2F441d6er59fl0dszh16kf.png" alt="Image description" width="800" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2- Procure por users e clique sobre: Create user&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%2Fslmamz1nbyrwshs3k7zi.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%2Fslmamz1nbyrwshs3k7zi.png" alt="Image description" width="800" height="152"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3- Escolha um nome de usuário &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%2F20gp5y8k8rnetw9czkie.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%2F20gp5y8k8rnetw9czkie.png" alt="Image description" width="800" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4- Na parte de policy escolha por: Attach policies directly&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%2F6zvzlc4ltf5dodmguz3f.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%2F6zvzlc4ltf5dodmguz3f.png" alt="Image description" width="800" height="218"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;5- Pesquise por Lambda e escolha a permissão: Lambda Full Access&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%2F73mzopqg6cngtl5alqqy.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%2F73mzopqg6cngtl5alqqy.png" alt="Image description" width="800" height="36"&gt;&lt;/a&gt;&lt;br&gt;
6- Revise as informações e clique sobre criar usuário &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%2F5t7mcjipfb4zdizyuolt.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%2F5t7mcjipfb4zdizyuolt.png" alt="Image description" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;7- De volta na nossa tela de usuários, clique sobre o nome de usuário que acabou de criar, e vá ate Security Credentials&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%2Fhr6uyzvo816mdyk57hhr.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%2Fhr6uyzvo816mdyk57hhr.png" alt="Image description" width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;8- Role a tela e procure a sessão de credentials keys e clique sobre Create Access Key&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%2Fzma2dpukgf4fhu7obq11.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%2Fzma2dpukgf4fhu7obq11.png" alt="Image description" width="800" height="174"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;9- Escolha a opção Outside AWS&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%2F3ox8ers8mh1hd3kx3vym.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%2F3ox8ers8mh1hd3kx3vym.png" alt="Image description" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;10- Clique sobre o botão create access key&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%2Fw5d7md3y81r0lsc2njpi.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%2Fw5d7md3y81r0lsc2njpi.png" alt="Image description" width="800" height="246"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configurando variáveis de ambiente no Github
&lt;/h2&gt;

&lt;p&gt;1- Crie o seu projeto no github&lt;/p&gt;

&lt;p&gt;2- Navegue ate em settings, no menu lateral escolha por Secrets and variables e escolha por Actions&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%2Fiju3qght8ye5h6nw4vkh.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%2Fiju3qght8ye5h6nw4vkh.png" alt="Image description" width="396" height="157"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3- Clique sobre o botão criar New Repository Secret&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%2Fpelgufy2rssnj2gxosyx.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%2Fpelgufy2rssnj2gxosyx.png" alt="Image description" width="800" height="204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4- Crie a primeira variavel com o nome de AWS_ACCESS_KEY_ID, no console da AWS copie sua Access key&lt;/p&gt;

&lt;p&gt;5- Logo após crie a variavel AWS_SECRET_ACCESS_KEYno console da AWS copie sua Secret access key&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%2Fb6ea74gkmaexf0rttt4d.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%2Fb6ea74gkmaexf0rttt4d.png" alt="Image description" width="800" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pronto, nosso ambiente de deploy está configurado para realizar deploys automáticos para a AWS.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>github</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>Automating Deployments to Heroku with GitHub Actions and Docker: Streamlining the Deployment Process</title>
      <dc:creator>Thiago Rodrigues</dc:creator>
      <pubDate>Tue, 08 Aug 2023 14:43:11 +0000</pubDate>
      <link>https://dev.to/thethiago27/automating-deployments-to-heroku-with-github-actions-and-docker-streamlining-the-deployment-process-1pc</link>
      <guid>https://dev.to/thethiago27/automating-deployments-to-heroku-with-github-actions-and-docker-streamlining-the-deployment-process-1pc</guid>
      <description>&lt;h2&gt;
  
  
  Tutorial: Automating Heroku Deployments with GitHub Actions and Docker: Streamlining the Deployment Process
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we'll delve into the process of utilizing GitHub Actions to automate the deployment of Docker images to Heroku. By the end of this tutorial, you'll have the know-how to achieve continuous deployment for a Fastify + TypeScript application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependencies
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm add &lt;span class="nt"&gt;-D&lt;/span&gt; typescript @types/node ts-node ts-node-dev
pnpm add fastify prisma @prisma/client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Script Configuration
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ts-node-dev --respawn --transpile-only --ignore-watch node_modules src/index.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ts-node src/index.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tsc"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting Up the Backend
&lt;/h2&gt;

&lt;p&gt;We'll start by setting up a simple backend since our primary goal lies elsewhere.&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fastify&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fastify&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fastify&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reply&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;world&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createServer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&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="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3001&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;HOST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HOST&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.0.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HOST&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="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Server is listening at &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;HOST&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;PORT&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="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="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="nx"&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 starting the server:&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="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exit&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Dockerfile Creation
&lt;/h2&gt;

&lt;p&gt;Next, let's craft a Dockerfile for our application. We'll employ the Docker multi-stage build approach, which allows us to create a production image that's considerably smaller than the development one, as we don't require all the development dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:16&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json ./&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; pnpm-lock.yaml ./&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; tsconfig.json ./&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; pnpm
&lt;span class="k"&gt;RUN &lt;/span&gt;pnpm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;npx prisma generate

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["pnpm", "run", "start"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  docker-compose.yml Setup
&lt;/h2&gt;

&lt;p&gt;Now, we'll create a docker-compose file to facilitate development.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.9"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;server_api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;stdin_open&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dockerfile&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3001:3001"&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;server_api&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.:/app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Understanding GitHub Actions
&lt;/h2&gt;

&lt;p&gt;GitHub Actions is a powerful tool provided by GitHub that enables you to automate various workflows, including building, testing, and deploying applications. It allows you to define custom workflows using YAML files, which can be triggered by events such as pushes, pull requests, or even on a schedule.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Workflow
&lt;/h2&gt;

&lt;p&gt;Let's proceed to establish the GitHub Actions workflow. For this, create a file named &lt;code&gt;deploy.yml&lt;/code&gt; within the &lt;code&gt;.github/workflows&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to Heroku&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;master&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build, Push and Release a Docker container to Heroku&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gonuit/heroku-docker-deploy@v1.3.3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.HEROKU_EMAIL }}&lt;/span&gt;
          &lt;span class="na"&gt;heroku_api_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.HEROKU_API_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;heroku_app_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.HEROKU_APP_NAME }}&lt;/span&gt;
          &lt;span class="na"&gt;dockerfile_directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./&lt;/span&gt;
          &lt;span class="na"&gt;dockerfile_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dockerfile&lt;/span&gt;
          &lt;span class="na"&gt;docker_options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--no-cache"&lt;/span&gt;
          &lt;span class="na"&gt;process_type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We define the workflow's name and specify that it should trigger on pushes to the &lt;code&gt;master&lt;/code&gt; branch.&lt;/li&gt;
&lt;li&gt;The workflow runs on an &lt;code&gt;ubuntu-latest&lt;/code&gt; virtual environment.&lt;/li&gt;
&lt;li&gt;We set up Node.js using the &lt;code&gt;actions/setup-node&lt;/code&gt; action.&lt;/li&gt;
&lt;li&gt;Dependencies are installed using &lt;code&gt;pnpm&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We build a Docker image for our Fastify app.&lt;/li&gt;
&lt;li&gt;We log in to the Heroku container registry.&lt;/li&gt;
&lt;li&gt;The Docker image is pushed to Heroku.&lt;/li&gt;
&lt;li&gt;Finally, the Docker image is released on Heroku.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Remember to replace &lt;code&gt;your-heroku-app-name&lt;/code&gt; with your actual Heroku app name.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finalizing
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we've covered a comprehensive process for automating the deployment of a Dockerized Fastify + TypeScript application to Heroku using GitHub Actions. We started by setting up the backend, creating a Dockerfile, and configuring the &lt;code&gt;docker-compose.yml&lt;/code&gt; file for easier development. We introduced GitHub Actions, explaining its significance in automating workflows. Finally, we created a GitHub Actions workflow that builds, pushes, and releases a Docker container to Heroku upon pushing changes to the &lt;code&gt;master&lt;/code&gt; branch.&lt;/p&gt;

&lt;p&gt;By embracing this automated deployment process, you can significantly enhance the efficiency and reliability of your application deployments, saving valuable time and minimizing manual errors.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>docker</category>
      <category>github</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Creating a Mixpanel Plugin with Fastify</title>
      <dc:creator>Thiago Rodrigues</dc:creator>
      <pubDate>Mon, 07 Aug 2023 22:46:43 +0000</pubDate>
      <link>https://dev.to/thethiago27/creating-a-mixpanel-plugin-with-fastify-59h4</link>
      <guid>https://dev.to/thethiago27/creating-a-mixpanel-plugin-with-fastify-59h4</guid>
      <description>&lt;h1&gt;
  
  
  Tutorial: Creating a Mixpanel Plugin with Fastify
&lt;/h1&gt;

&lt;p&gt;In this tutorial, you will learn how to create a Mixpanel plugin to track errors and request events in a Fastify application using JavaScript. Mixpanel is an analytics platform that allows you to track and analyze user events in applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Environment Setup
&lt;/h2&gt;

&lt;p&gt;Make sure you have Node.js installed on your system. If you haven't already, you can download it from &lt;a href="https://nodejs.org/"&gt;nodejs.org&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Initializing a Fastify Project
&lt;/h2&gt;

&lt;p&gt;Open a terminal and create a new folder for your project. Navigate to this folder using the terminal and execute the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;my-mixpanel-project
&lt;span class="nb"&gt;cd &lt;/span&gt;my-mixpanel-project
npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;fastify mixpanel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Creating the Mixpanel Plugin
&lt;/h2&gt;

&lt;p&gt;Create a new file called &lt;code&gt;mixpanel-plugin.js&lt;/code&gt; in the root folder of your project. Open this file in a code editor and copy the following code:&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;// mixpanel-plugin.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;mixpanel&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mixpanel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fp&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fastify-plugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;FastifyError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;FastifyInstance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;FastifyPluginAsync&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;FastifyRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fastify&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;mixpanelPlugin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FastifyPluginAsync&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fastify&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FastifyInstance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_&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="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;MIXPANEL_TOKEN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MIXPANEL_TOKEN&lt;/span&gt; &lt;span class="o"&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;mixpanelClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mixpanel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MIXPANEL_TOKEN&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;fastify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;onError&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FastifyRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FastifyError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;mixpanelClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;track&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="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;error&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="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;stack&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="nx"&gt;stack&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;request&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="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;fastify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;onRequest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FastifyRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eventData&lt;/span&gt; &lt;span class="o"&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;request&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="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;request&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="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="nx"&gt;mixpanelClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Request URL &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;request&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;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;eventData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;mixpanelPlugin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Creating the Fastify Application
&lt;/h2&gt;

&lt;p&gt;Create a new file called &lt;code&gt;app.js&lt;/code&gt; in the root folder of your project. Open this file in a code editor and copy the following code:&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;// app.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fastify&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fastify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;mixpanelPlugin&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./mixpanel-plugin&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fastify&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Register the Mixpanel plugin&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mixpanelPlugin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Define an example route&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, world!&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;// Start the server&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&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="nx"&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 starting the server:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server started on port 3000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Running the Application
&lt;/h2&gt;

&lt;p&gt;In the terminal, execute the following command to start the Fastify server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node app.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything is set up correctly, you will see the message "Server started on port 3000". Now, your application is running, and the Mixpanel plugin will start tracking errors and request events.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations! You've created a Mixpanel plugin to track errors and request events in a Fastify application. Now you have a solid foundation for implementing analytics and event tracking in your projects.&lt;/p&gt;

&lt;p&gt;Remember to replace &lt;code&gt;MIXPANEL_TOKEN&lt;/code&gt; with your actual Mixpanel token and adjust the code according to your needs. This tutorial provided an introduction to the concept of plugins in Fastify and how to integrate Mixpanel for event tracking.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>The Journey of an Artificial Intelligence Recommending Taylor Swift's Songs</title>
      <dc:creator>Thiago Rodrigues</dc:creator>
      <pubDate>Mon, 07 Aug 2023 22:16:21 +0000</pubDate>
      <link>https://dev.to/thethiago27/the-journey-of-an-artificial-intelligence-recommending-taylor-swifts-songs-3eb2</link>
      <guid>https://dev.to/thethiago27/the-journey-of-an-artificial-intelligence-recommending-taylor-swifts-songs-3eb2</guid>
      <description>&lt;p&gt;It's not exactly a thunderous revelation that in recent times we've all been practically run over by a name resonating like a musical tsunami: Taylor Swift. And I'll be honest, my obsession with her lyrical ability is so obvious that it would be easier to hide it in a packed stadium from The Eras than to search for all the hidden Easter eggs in "Look What You Made Me Do." It's as if she has a song ready for every micro-moment in life, whether you're in the dumps or at the peak of a wild party.&lt;/p&gt;

&lt;p&gt;So, I got to thinking... could we create a kind of electronic guru, an artificial intelligence, that selects the perfect Taylor Swift soundtrack according to your current mood? And thus was born Dorothea AI, my modern version of a musical advisor, but with a healthy dose of technological cuteness. To train this beauty, I fed her with 233 songs, leaving aside the original versions and focusing solely on the editions stamped with the "taylor’s versions" seal (after all, we don't listen to stolen versions).&lt;/p&gt;

&lt;p&gt;All of this wouldn't have been possible without the magic of TensorFlow and the hands-on approach of Python, which were the secret ingredients of the recipe. Now, if you want to take a peek at the result of this slightly crazy experiment, just click &lt;a href="https://whatsmytaylorswiftsong.vercel.app"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Oh, and of course, if you're the curious type who likes to tinker with gears, the entire process is neatly stored in &lt;a href="https://github.com/thethiago27/dorothea_ia"&gt;this digital vault&lt;/a&gt;. Who knows, maybe you'll be inspired to create the next AI that chooses songs based on the weather? The sky's the limit, my friend!&lt;/p&gt;

</description>
      <category>tensorflow</category>
      <category>python</category>
      <category>taylorswift</category>
      <category>node</category>
    </item>
  </channel>
</rss>
