<?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: Guilherme Camargo</title>
    <description>The latest articles on DEV Community by Guilherme Camargo (@guisfits).</description>
    <link>https://dev.to/guisfits</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%2F38353%2F09f2fe11-db3e-4d02-85b5-6dc42c45865d.png</url>
      <title>DEV Community: Guilherme Camargo</title>
      <link>https://dev.to/guisfits</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/guisfits"/>
    <language>en</language>
    <item>
      <title>Construindo uma API com Deno: Da instalação ao Deploy</title>
      <dc:creator>Guilherme Camargo</dc:creator>
      <pubDate>Thu, 18 Jun 2020 21:47:06 +0000</pubDate>
      <link>https://dev.to/guisfits/construindo-uma-api-com-deno-da-instalacao-ao-deploy-2gii</link>
      <guid>https://dev.to/guisfits/construindo-uma-api-com-deno-da-instalacao-ao-deploy-2gii</guid>
      <description>&lt;p&gt;Criei minha primeira API com &lt;strong&gt;Deno&lt;/strong&gt; recentemente e decidi compartilhar tudo que aprendi sobre ele neste artigo. &lt;/p&gt;

&lt;p&gt;Esta API é parte de um projeto open-source que estou desenvolvendo. Meu objetivo com ele é implementar um "e-commerce" seguindo a arquitetura de microservices, com a stack JS, e aprender outras tecnologias no processo. Todo o código que usei está no meu &lt;a href="https://github.com/guisfits/easy-commerce/tree/master/services/rating"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é o Deno
&lt;/h2&gt;

&lt;p&gt;Deno &lt;del&gt;como todos já estão cansados de ouvir&lt;/del&gt; é o novo runtime JS/TS, feito pelo mesmo criador do Node, Ryan Dahl. Ele possui fortes restrições de segurança, é construído com a linguagem Rust, em cima da V8 do Google e tem &lt;del&gt;uma meia&lt;/del&gt; um &lt;strong&gt;dino&lt;/strong&gt;ssauro de mascote.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xFlE5M6o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://deno.land/images/deno_logo_4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xFlE5M6o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://deno.land/images/deno_logo_4.gif" alt="logo" width="240" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Vou sair um pouco do convencional e mostrar uma alternativa pra instalar o Deno - ou qualquer outro runtime que queira. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/asdf-vm/asdf"&gt;asdf&lt;/a&gt; é um gerenciador de versão universal. Após instalá-lo com o &lt;a href="https://asdf-vm.com/#/core-manage-asdf-vm"&gt;guia oficial&lt;/a&gt; rode os seguintes comandos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;asdf plugin-add deno https://github.com/asdf-community/asdf-deno.git
&lt;span class="nv"&gt;$ &lt;/span&gt;asdf &lt;span class="nb"&gt;install &lt;/span&gt;deno 1.0.5
&lt;span class="nv"&gt;$ &lt;/span&gt;asdf global deno 1.0.5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Como estou usando a versão 1.0.5 nos exemplos, deixei fixo aqui, mas você pode repetir os últimos dois comandos com "latest" e usar a versão mais atual depois.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Para conferir se deu tudo certo é só rodar &lt;code&gt;$ deno --version&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup Environment
&lt;/h2&gt;

&lt;h3&gt;
  
  
  VS Code extension
&lt;/h3&gt;

&lt;p&gt;VS Code se tornou o ambiente padrão para muitas linguagens, acredito que JS/TS seja a maior delas. Já temos uma &lt;a href="https://marketplace.visualstudio.com/items?itemName=denoland.vscode-deno"&gt;extensão&lt;/a&gt; criada pela equipe do Deno que nos dará um suporte melhor durante o desenvolvimento. &lt;/p&gt;

&lt;h3&gt;
  
  
  VS Code settings
&lt;/h3&gt;

&lt;p&gt;Após instalar a extensão do Deno precisamos &lt;em&gt;setar&lt;/em&gt; a versão do Typescript que o VS Code usa para a última versão. Se ainda não instalou - e considerando que você já tenha Node instalado na sua máquina - rode &lt;code&gt;$ npm i -g typescript&lt;/code&gt;. Agora precisamos obter o caminho para os executáveis. No terminal rode &lt;code&gt;$ npm list -g typescript&lt;/code&gt;, ele irá nos dizer o caminho até a pasta raiz onde o TS foi instalado, navegue até lá e vá para a pasta "lib", rode &lt;code&gt;$ pwd&lt;/code&gt;, copie todo o caminho e cole na propriedade &lt;code&gt;"typescript.tsdk"&lt;/code&gt; no &lt;code&gt;settings.json&lt;/code&gt; global do VS Code ou do workspace. &lt;/p&gt;

&lt;p&gt;No meu caso estou usando o settings do workspace com algumas outras configurações, recomendo usar as mesmas.&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="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;typescript.tsdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;~/.asdf/installs/nodejs/12.18.0/.npm/lib/node_modules/typescript/lib&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[typescript]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;editor.defaultFormatter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vscode.typescript-language-features&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;deno.enable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;deno.unstable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Variáveis de ambiente
&lt;/h3&gt;

&lt;p&gt;O Deno usa uma pasta global na sua máquina para salvar algumas coisas. Caso não tenha sido criada ainda rode &lt;code&gt;$ mkdir -p ~/.deno/bin&lt;/code&gt;. Este será o caminho onde ficará alguns executáveis que instalaremos com o Deno. Agora precisamos que nosso terminal olhe para esta pasta quando for procurar pelos binários. Abra o arquivo de configuração do seu terminal (&lt;code&gt;.bashrc&lt;/code&gt;, &lt;code&gt;.zshrc&lt;/code&gt;, ...) e cole isso no início do arquivo.&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;export &lt;/span&gt;&lt;span class="nv"&gt;DENO_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.deno
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;:&lt;span class="nv"&gt;$DENO_DIR&lt;/span&gt;/bin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Recomendo que feche e abra uma nova instância do terminal para que reflita as alterações.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Typescript
&lt;/h3&gt;

&lt;p&gt;O projeto será full typescript. Você pode usar JS puro se preferir, mas prefiro TS, gosto muito do &lt;em&gt;tooling&lt;/em&gt; que ele me dá e ele me ajuda a evitar erros bobos. Além disso, TS é a linguagem recomendada para desenvolver com Deno. &lt;/p&gt;

&lt;p&gt;Apesar de não ser necessário geralmente, neste projeto iremos utilizar &lt;em&gt;decorators&lt;/em&gt; e para isso precisamos dizer ao TS para aceitar essa sintaxe. Para isso temos que criar o arquivo &lt;code&gt;tsconfig.json&lt;/code&gt; dentro da pasta &lt;code&gt;src&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;compilerOptions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;experimentalDecorators&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;emitDecoratorMetadata&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Estrutura do projeto
&lt;/h2&gt;

&lt;p&gt;Esta API será responsável por cadastrar as avaliações dos usuários para os produtos que eles comprarem. &lt;/p&gt;

&lt;p&gt;Só teremos duas rotas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;POST&lt;/strong&gt; /ratings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GET&lt;/strong&gt; /ratings
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A estrutura final do projeto será esta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── .env
├── .env.example
├── .vscode
│   ├── launch.json
│   └── settings.json
├── Dockerfile
├── denon.json
├── docker-compose.yml
└── src
    ├── controllers
    │   └── rating.controller.ts
    ├── database
    │   ├── connection.ts
    │   ├── entities
    │   │   ├── buyer.entity.ts
    │   │   ├── product.entity.ts
    │   │   └── rating.entity.ts
    │   └── repositories
    │       ├── buyer.repository.ts
    │       ├── product.repository.ts
    │       └── rating.repository.ts
    ├── deps.ts
    ├── env.ts
    ├── routes.ts
    ├── server.ts
    └── tsconfig.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Framework Web
&lt;/h2&gt;

&lt;p&gt;O Deno tem uma ótima &lt;a href="https://deno.land/std"&gt;standard library&lt;/a&gt;, porém não queremos trabalhar com a classe de http diretamente, pois teríamos que fazer muita coisa na mão, é por isso que usamos frameworks. No Node o comum é o &lt;em&gt;express&lt;/em&gt;,  no Deno o framework mais estável e com mais uso até o momento é o &lt;a href="https://deno.land/x/oak"&gt;oak&lt;/a&gt; - ele é baseado no &lt;em&gt;koa&lt;/em&gt; &lt;del&gt;pessoal do Deno adoram fazer anagramas&lt;/del&gt;. &lt;/p&gt;

&lt;p&gt;A primeira coisa que precisamos criar é o arquivo &lt;code&gt;server.ts&lt;/code&gt;, que será o arquivo de entrada para a aplicação.&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Application&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;https://deno.land/x/oak/mod.ts&lt;/span&gt;&lt;span class="dl"&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Application&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;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8001&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Running on port &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="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="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;({&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;port&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora podemos rodar usando &lt;code&gt;$ deno run --allow-net server.ts&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Imports
&lt;/h3&gt;

&lt;p&gt;A primeira coisa que vemos de diferente em comparação com o Node é que no Deno usamos &lt;em&gt;ES Modules&lt;/em&gt; ao invés do &lt;em&gt;CommonJS&lt;/em&gt; e estamos dando &lt;code&gt;import&lt;/code&gt; de uma URL direto no nosso código. Isso pode parecer meio estranho - Deno se inspirou na linguagem &lt;strong&gt;Go&lt;/strong&gt; neste aspecto - porém no browser isso sempre foi comum. É como a tag &lt;code&gt;script&lt;/code&gt; do &lt;strong&gt;HTML&lt;/strong&gt; funciona: &lt;code&gt;&amp;lt;script src="URL"&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  node_modules / package.json
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Então se estamos importando as dependências via URL, toda vez que quisermos rodar a aplicação teremos de ter acesso à internet?&lt;/li&gt;
&lt;li&gt;Não!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Assim que usamos uma nova dependência o Deno baixa o código desta URL para um cache em uma pasta global na sua máquina - o caminho padrão é &lt;code&gt;~/.deno/deps/https&lt;/code&gt;. Na próxima vez que rodarmos esta aplicação, ou outra que tenha a mesma dependência, o Deno irá obter a dependência desta pasta. &lt;/p&gt;

&lt;p&gt;Dito isso, não precisamos mais de uma pasta na raiz do nosso projeto como o &lt;code&gt;node_modules&lt;/code&gt;. Se, por exemplo, temos duas APIs com Deno que usam a mesma versão do &lt;em&gt;oak&lt;/em&gt;, não teremos ele duplicado duas vezes na nossa máquina. &lt;/p&gt;

&lt;p&gt;Como &lt;strong&gt;não instalamos as dependências&lt;/strong&gt;, só fazemos referência, também não precisamos mais do arquivo &lt;code&gt;package.json&lt;/code&gt;. A única coisa que precisamos é do próprio arquivo JS/TS.&lt;/p&gt;

&lt;h3&gt;
  
  
  deps.ts
&lt;/h3&gt;

&lt;p&gt;O ponto ruim de fazer referência via URL é que, dependendo do tamanho do projeto, você ficará com URLs espalhadas por toda a aplicação. E caso queira atualizar uma dependência para outra versão, remover ou até mesmo saber quais libs estão sendo usadas, você não terá isso em um ponto centralizado. &lt;/p&gt;

&lt;p&gt;Pensando nisso podemos centralizar essas referências em um arquivo e importar o que precisamos deste arquivo.&lt;/p&gt;

&lt;p&gt;Dentro de &lt;code&gt;src&lt;/code&gt; crie o arquivo &lt;code&gt;deps.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nx"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Context&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="s2"&gt;https://deno.land/x/oak/mod.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Top level await
&lt;/h3&gt;

&lt;p&gt;Outra coisa interessante que estamos usando é &lt;code&gt;await&lt;/code&gt; sem uma função &lt;code&gt;async&lt;/code&gt;. Deno tem esta &lt;em&gt;feature&lt;/em&gt; &lt;a href="https://v8.dev/features/top-level-await"&gt;graças ao V8&lt;/a&gt;, onde podemos usar &lt;code&gt;await&lt;/code&gt; direto na raiz do arquivo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Denon
&lt;/h2&gt;

&lt;p&gt;Assim como no Node usamos o &lt;em&gt;Nodemon&lt;/em&gt; para que a aplicação reinicie toda vez que um arquivo é alterado, no Deno usamos o &lt;em&gt;denon&lt;/em&gt;. Após instalá-lo seguindo o &lt;a href="https://deno.land/x/denon"&gt;readme&lt;/a&gt;, vamos criar um arquivo chamado &lt;code&gt;denon.json&lt;/code&gt; na raiz do projeto. Ele é muito útil, podemos fazer varias configurações de como nossa aplicação deve rodar.&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="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$schema&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://deno.land/x/denon/schema.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;allow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;env&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;net&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tsconfig&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src/tsconfig.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unstable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scripts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cmd&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src/server.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;env&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;APP_PORT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;8001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logger&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;debug&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;allow&lt;/code&gt; é onde damos as permissões do que o Deno pode executar na nossa máquina.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tsconfig&lt;/code&gt; é pra dizermos pro Deno considerar nossas configurações extras do TS; &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;unstable&lt;/code&gt; pois nem todas as funcionalidades do deno e de algumas libs estão prontas;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scripts&lt;/code&gt; é onde criamos configurações específicas. Podemos dar qualquer nome, coloquei &lt;em&gt;start&lt;/em&gt; por convenção mesmo; &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cmd&lt;/code&gt; temos só nome do arquivo de &lt;em&gt;entry-point&lt;/em&gt; para aplicação, mas ele irá executar &lt;code&gt;$ deno run...&lt;/code&gt; antes;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;env&lt;/code&gt; para exportar variáveis de ambientes que só esta aplicação irá usar;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;logger&lt;/code&gt; para termos um log mais detalhado no terminal;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Assim que rodarmos &lt;code&gt;$ denon start&lt;/code&gt; você notará que o que ele realmente executa é &lt;code&gt;$ deno run --allow-env --allow-net --config src/tsconfig.json --unstable src/server.ts&lt;/code&gt;. Imagina ter que lembrar e digitar tudo isso toda vez? &lt;em&gt;Denon&lt;/em&gt; é opcional, mas extremamente útil.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debuging
&lt;/h2&gt;

&lt;p&gt;Pra melhorar ainda mais nossa experiência com Deno podemos debugar a aplicação pelo VS Code.&lt;/p&gt;

&lt;p&gt;Basta criar o arquivo &lt;code&gt;.vscode/launch.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;version&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.2.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;configurations&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Deno&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;request&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;launch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cwd&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${workspaceFolder}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;runtimeExecutable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;deno&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;runtimeArgs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;run&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--unstable&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--config&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src/tsconfig.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--inspect-brk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-A&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src/server.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;port&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;9229&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;
  
  
  Camada de dados
&lt;/h2&gt;

&lt;h3&gt;
  
  
  TypeORM
&lt;/h3&gt;

&lt;p&gt;Acho ORM uma ferramenta indispensável. Trabalhar direto com SQL no código - além de deixar tudo mais sujo, extenso e complexo - abre brechas de segurança e possibilidade de vários bugs. ORMs encapsulam toda essa complexidade e nos oferecem uma interface simples, testada e a possibilidade de usar a mesma estrutura da linguagem com o restante da aplicação. &lt;/p&gt;

&lt;p&gt;Não foi fácil encontrar um ORM que funcionasse direito no Deno, testei alguns e o que acabei mais gostando foi um &lt;a href="https://github.com/denolib/typeorm"&gt;fork do TypeORM&lt;/a&gt; que já existia no Node.&lt;/p&gt;

&lt;p&gt;Dentro do arquivo &lt;code&gt;deps.ts&lt;/code&gt; vamos adicionar esta nova dependência&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;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nx"&gt;createConnection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="nx"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="nx"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="nx"&gt;PrimaryGeneratedColumn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="nx"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="nx"&gt;OneToMany&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ManyToOne&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Repository&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="s2"&gt;https://denolib.com/denolib/typeorm@v0.2.23-rc4/mod.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Até o momento da publicação deste artigo este fork está em &lt;em&gt;release candidate&lt;/em&gt; ainda, muitas coisas podem não funcionar corretamente. &lt;strong&gt;Paciência você deve ter.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/26mfgpNiKHawv3wDS/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/26mfgpNiKHawv3wDS/giphy.gif" alt="yoda" width="480" height="206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Entities
&lt;/h3&gt;

&lt;p&gt;A primeira coisa que devemos fazer é criar as entidades. Dentro da pasta &lt;code&gt;src/database/entities&lt;/code&gt; crie os seguintes arquivos&lt;/p&gt;

&lt;h4&gt;
  
  
  buyer.entity.ts
&lt;/h4&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PrimaryGeneratedColumn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OneToMany&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="s2"&gt;../../deps.ts&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;Rating&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./rating.entity.ts&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="nd"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;buyers&lt;/span&gt;&lt;span class="dl"&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Buyer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;PrimaryGeneratedColumn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;varchar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;fullName&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;OneToMany&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Rating&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buyer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;ratings&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Rating&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  product.entity.ts
&lt;/h4&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PrimaryGeneratedColumn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OneToMany&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="s2"&gt;../../deps.ts&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;Rating&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./rating.entity.ts&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="nd"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;products&lt;/span&gt;&lt;span class="dl"&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;PrimaryGeneratedColumn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;varchar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;OneToMany&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Rating&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;ratings&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Rating&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  rating.entity.ts
&lt;/h4&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PrimaryGeneratedColumn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ManyToOne&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="s2"&gt;../../deps.ts&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;Product&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./product.entity.ts&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;Buyer&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./buyer.entity.ts&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="nd"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ratings&lt;/span&gt;&lt;span class="dl"&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Rating&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;PrimaryGeneratedColumn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;int&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;comment&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ManyToOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ratings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ManyToOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Buyer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ratings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;buyer&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Buyer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como pode ver, toda configuração referente ao banco de dados é feita com &lt;em&gt;decorators&lt;/em&gt; dentro do TypeORM. Isso é muito legal pois podemos utilizar a mesma classe em outro cenários sem sujá-la com propriedades referente a como os dados estão armazenados. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O &lt;em&gt;decorator&lt;/em&gt; &lt;code&gt;@Entity()&lt;/code&gt; torna nossa classe uma tabela dentro do banco, caso queira você pode dizer o nome que esta tabela terá; &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@PrimaryGeneratedColumn&lt;/code&gt; diz que o campo &lt;code&gt;id&lt;/code&gt; é a chave-primária e será auto-incrementável;&lt;/li&gt;
&lt;li&gt;Com &lt;code&gt;@Column()&lt;/code&gt; fazemos as configurações que a coluna terá no banco;&lt;/li&gt;
&lt;li&gt;Para fazer relacionamento no TypeORM mantemos um campo com o tipo da classe relacionada como referência e usamos o &lt;em&gt;decorator&lt;/em&gt; &lt;code&gt;OneToOne()&lt;/code&gt;, &lt;code&gt;OneToMany()&lt;/code&gt;, &lt;code&gt;ManyToOne()&lt;/code&gt; ou &lt;code&gt;ManyToMany()&lt;/code&gt; neste campo. Sempre lembrando de fazer tanto a ida quanto a volta para ambas as entidades. Repare que na entidade &lt;code&gt;Rating&lt;/code&gt; não criamos a &lt;code&gt;foreign key&lt;/code&gt; para &lt;code&gt;Product&lt;/code&gt; nem &lt;code&gt;Buyer&lt;/code&gt;, o TypeORM faz isso pra gente e nos deixa trabalhar direto com a classe. Muito massa isso 😃&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Há diversos outros &lt;em&gt;decorators&lt;/em&gt; e opções para os mais diversos cenários dentro do TypeORM. Recomendo olhar a &lt;a href="https://github.com/denolib/typeorm/tree/master/docs"&gt;documentação&lt;/a&gt; para casos mais complexos. &lt;/p&gt;

&lt;h3&gt;
  
  
  Connection
&lt;/h3&gt;

&lt;p&gt;Entidades criadas, agora vamos criar a conexão com o banco. &lt;/p&gt;

&lt;p&gt;Dentro da pasta &lt;code&gt;src/database&lt;/code&gt; crie o arquivo &lt;code&gt;connection.ts&lt;/code&gt; com essas configurações:&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createConnection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Connection&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="s2"&gt;../deps.ts&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;Buyer&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./entities/buyer.entity.ts&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;Product&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./entities/product.entity.ts&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;Rating&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./entities/rating.entity.ts&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;env&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../env.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RatingConnection&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createConnection&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;postgres&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_HOST&lt;/span&gt;&lt;span class="p"&gt;,&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;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_PORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;username&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;DB_USERNAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;password&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;DB_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;database&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;DB_DATABASE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="nx"&gt;Rating&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;Buyer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;synchronize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connection&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;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="nf"&gt;error&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="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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RatingConnection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;syncroniz&lt;/code&gt; irá deixar o banco igual nossas entidades, criando as tabelas e removendo as que não existem;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;logger&lt;/code&gt; para vermos as &lt;em&gt;queries&lt;/em&gt; que a aplicação fará no terminal;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Irei falar sobre &lt;em&gt;postgres&lt;/em&gt; e o &lt;code&gt;env.ts&lt;/code&gt; logo abaixo. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Repositories
&lt;/h3&gt;

&lt;p&gt;Com TypeORM conseguimos usar um &lt;em&gt;query-builder&lt;/em&gt; muito poderoso, podemos fazer &lt;em&gt;queries&lt;/em&gt; complexas com código JS/TS. Fazemos essas &lt;em&gt;queries&lt;/em&gt; a partir da &lt;code&gt;connection&lt;/code&gt;, porém o TypeORM oferece a opção de criar um &lt;a href="https://martinfowler.com/eaaCatalog/repository.html"&gt;repository&lt;/a&gt; padrão com muitos métodos comuns. A partir da &lt;code&gt;connection&lt;/code&gt; chamamos o método &lt;code&gt;getRepository&lt;/code&gt; passando o tipo da &lt;code&gt;Entity&lt;/code&gt; no parâmetro. Isso irá retornar um novo objeto do tipo &lt;code&gt;Repository&amp;lt;TEntity&amp;gt;&lt;/code&gt; que possui métodos como: &lt;code&gt;getId&lt;/code&gt;, &lt;code&gt;create&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;delete&lt;/code&gt;, &lt;code&gt;find&lt;/code&gt;, &lt;code&gt;findOne&lt;/code&gt;, entre outros. &lt;/p&gt;

&lt;p&gt;Dentro da pasta &lt;code&gt;src/database/repositories&lt;/code&gt; vamos criar os seguintes arquivos:&lt;/p&gt;

&lt;h4&gt;
  
  
  buyer.repository.ts
&lt;/h4&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Repository&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;../../deps.ts&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;RatingConnection&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;../connection.ts&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;Buyer&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;../entities/buyer.entity.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BuyerRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;_instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Repository&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Buyer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;RatingConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;getRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Buyer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_instance&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BuyerRepository&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  product.repository.ts
&lt;/h4&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Repository&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;../../deps.ts&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;Product&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;../entities/product.entity.ts&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;RatingConnection&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;../connection.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;_instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Repository&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;RatingConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;getRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_instance&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ProductRepository&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  rating.repository.ts
&lt;/h4&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Repository&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;../../deps.ts&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;Rating&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;../entities/rating.entity.ts&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;RatingConnection&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;../connection.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RatingRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;_instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Repository&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Rating&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;RatingConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;getRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Rating&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_instance&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RatingRepository&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Basicamente estamos criando uma classe com um método &lt;em&gt;singleton&lt;/em&gt; que irá retornar uma instância do &lt;em&gt;repository&lt;/em&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No TypeORM podemos usar o &lt;em&gt;decorator&lt;/em&gt; &lt;code&gt;@EntityRepository(TEntity)&lt;/code&gt; para criar esses &lt;em&gt;repositories&lt;/em&gt; de maneira automática, porém essa versão apresentou alguns problemas. Uma alternativa seria usar uma lib de &lt;em&gt;dependency injection&lt;/em&gt;, mas não vi a necessidade disso pra este projeto.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Controllers
&lt;/h3&gt;

&lt;p&gt;Camada de dados pronta, agora vamos criar os &lt;em&gt;endpoints&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Dentro da pasta &lt;code&gt;src/controllers&lt;/code&gt; crie o arquivo &lt;code&gt;rating.controller.ts&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Context&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="s2"&gt;../deps.ts&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;RatingRepository&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;../database/repositories/rating.repository.ts&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;BuyerRepository&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;../database/repositories/buyer.repository.ts&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;ProductRepository&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;../database/repositories/product.repository.ts&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;Rating&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;../database/entities/rating.entity.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RatingController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="p"&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;ratings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;RatingRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createQueryBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ratings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ratings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;product.name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;buyer.fullName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;leftJoin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ratings.product&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;product&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;leftJoin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ratings.buyer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;buyer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMany&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ratings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Rating&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;buyer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buyer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;product&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="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;async&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="p"&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;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buyerId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;productId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;invalid rate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&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;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ProductRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;productId&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;buyer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;BuyerRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;buyerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;buyer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&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;rating&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Rating&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buyer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buyer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;comment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rate&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;RatingRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rating&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RatingController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Primeiro importamos os &lt;em&gt;repositories&lt;/em&gt;. O método &lt;code&gt;index&lt;/code&gt; irá retornar um array de &lt;code&gt;Rating&lt;/code&gt;, a partir do &lt;code&gt;RatingRepository&lt;/code&gt; fazemos a &lt;em&gt;query&lt;/em&gt; dando &lt;em&gt;join&lt;/em&gt; nas tabelas relacionadas e &lt;em&gt;select&lt;/em&gt; nos campos que iremos usar. O método &lt;code&gt;create&lt;/code&gt; irá cadastrar um novo &lt;code&gt;Rating&lt;/code&gt;, após pegar os dados do &lt;code&gt;body&lt;/code&gt; fazemos uma validação, depois pegamos as entidades relacionadas e, caso não forem nulas, salvamos um novo &lt;code&gt;Rating&lt;/code&gt;. Bem simples. &lt;/p&gt;

&lt;h3&gt;
  
  
  Rotas
&lt;/h3&gt;

&lt;p&gt;Agora dentro de &lt;code&gt;src&lt;/code&gt; crie &lt;code&gt;router.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Router&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;./deps.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;RatingController&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;./controllers/rating.controller.ts&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;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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;/ratings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RatingController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/ratings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RatingController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&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;router&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Server.ts
&lt;/h3&gt;

&lt;p&gt;Fizemos várias alterações. Agora precisamos voltar ao &lt;code&gt;server.ts&lt;/code&gt; e atualizá-lo com as novas classes.&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Application&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;./deps.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;env&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;./env.ts&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;router&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;./routes.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;RatingConnection&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;./database/connection.ts&lt;/span&gt;&lt;span class="dl"&gt;'&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;RatingConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Application&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="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;routes&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="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;allowedMethods&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Running on port &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;APP_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="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="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;({&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;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;APP_PORT_INTERNAL&lt;/span&gt; &lt;span class="o"&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;APP_PORT&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploy
&lt;/h2&gt;

&lt;h3&gt;
  
  
  .env
&lt;/h3&gt;

&lt;p&gt;Toda aplicação tem dados sensíveis que mudam de ambiente para ambiente. É prática comum exportar esses valores quando rodamos a aplicação e obtê-los durante o runtime. Para sabermos quais dados devemos passar criamos um arquivo chamado &lt;code&gt;.env.example&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Application
APP_PORT=
APP_PORT_INTERNAL=
APP_ENVIRONMENT=

# Database
DB_HOST=
DB_PORT=
DB_USERNAME=
DB_PASSWORD=
DB_DATABASE=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com esse template copiamos todos as variáveis e criamos outro arquivo chamado &lt;code&gt;.env&lt;/code&gt; com os devidos valores. &lt;strong&gt;Não devemos versionar este último, ele deve existir somente no ambiente na qual a aplicação irá rodar.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Podemos também passar esses valores dentro da chave &lt;code&gt;env&lt;/code&gt; do &lt;code&gt;denon.json&lt;/code&gt; ou usar alguma lib que lê este tipo de arquivo e o carrega no environment do runtime.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Dockerfile
&lt;/h3&gt;

&lt;p&gt;Docker é uma das ferramentas mais usadas no desenvolvimento de software atualmente. Me atrevo a dizer que saber Docker hoje em dia é quase tão importante quanto saber Git. Ele é muito prático e nos ajuda em várias coisas. &lt;/p&gt;

&lt;p&gt;Não existe uma imagem oficial do Deno até o momento, o mais próximo disso é &lt;a href="https://hub.docker.com/r/hayd/deno"&gt;esta imagem&lt;/a&gt; que está sendo cogitada nas &lt;a href="https://github.com/denoland/deno/issues/3356"&gt;issues do GitHub&lt;/a&gt;.&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; hayd/deno:alpine-1.0.5&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3333&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;USER&lt;/span&gt;&lt;span class="s"&gt; deno&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src/deps.ts /app&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;deno cache &lt;span class="nt"&gt;--unstable&lt;/span&gt; deps.ts

&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="s"&gt; /src /app&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;deno cache &lt;span class="nt"&gt;-c&lt;/span&gt; tsconfig.json &lt;span class="nt"&gt;--unstable&lt;/span&gt; server.ts

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["run", "--allow-env", "--allow-net", "--config", "tsconfig.json", "--unstable", "server.ts" ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cada comando no Docker é como uma camada, onde a anterior se torna a base para as próximas. Com isso em mente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Primeiro obtemos a imagem base com &lt;strong&gt;FROM&lt;/strong&gt;. Estamos usando a versão &lt;em&gt;alpine&lt;/em&gt;, que é uma versão mais leve do linux. Estamos usando a versão 1.0.5 do Deno também. É boa prática sempre dizer a versão que sua aplicação usa para não atualizar de uma hora pra outra e, possivelmente, quebrar o sistema;&lt;/li&gt;
&lt;li&gt;Em seguida expomos a porta 3333 onde podemos receber requisições;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WORKDIR&lt;/strong&gt; é basicamente um &lt;code&gt;$ cd&lt;/code&gt; dentro do container. Ele cria a pasta, caso ainda não exista;&lt;/li&gt;
&lt;li&gt;Mudamos de usuário &lt;em&gt;root&lt;/em&gt; com &lt;strong&gt;USER&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;Aqui um ponto importante. Copiamos o arquivo &lt;code&gt;deps.ts&lt;/code&gt; e fazemos o cache dele. Este comando só será executado novamente caso as dependências mudem;&lt;/li&gt;
&lt;li&gt;Depois copiamos o restante da pasta &lt;code&gt;src&lt;/code&gt; para dentro do container e &lt;em&gt;cacheamos&lt;/em&gt; o &lt;code&gt;server.ts&lt;/code&gt; para que não seja compilado toda vez que rodarmos uma nova instância do container. &lt;/li&gt;
&lt;li&gt;E por último, &lt;strong&gt;CMD&lt;/strong&gt; irá executar os argumentos dentro do array toda vez que o container for iniciado.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fazendo uma analogia com OOP: O &lt;code&gt;Dockerfile&lt;/code&gt; é como uma classe - onde definimos o &lt;em&gt;shape&lt;/em&gt; que nosso container terá - e o container é o objeto instanciado.&lt;/p&gt;

&lt;h3&gt;
  
  
  docker-compose
&lt;/h3&gt;

&lt;p&gt;Para instanciar um container precisamos passar diversos argumentos pelo terminal. Lembrando também que um sistema geralmente não funciona sozinho - no BackEnd, por exemplo, temos a aplicação e o banco de dados. Pra conectar ambos pelo docker precisamos criar uma &lt;code&gt;network&lt;/code&gt;. No caso do banco de dados, precisamos passar o &lt;code&gt;volume&lt;/code&gt; para manter os dados persistidos. Além disso podemos passar as variáveis de ambiente, expor portas, entre outras coisas.&lt;/p&gt;

&lt;p&gt;Para gerenciar tudo isso temos o &lt;code&gt;docker-compose&lt;/code&gt;. Sua função é configurar todos os containers que precisamos, com todos os argumentos, e conectá-los.&lt;/p&gt;

&lt;p&gt;Iremos criar dois containers&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;app&lt;/strong&gt; que fará o build da aplicação e configurar seus parâmetros de entrada;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;database&lt;/strong&gt; onde iremos configurar um banco de dados da nossa escolha. No meu caso escolhi o &lt;code&gt;postgres&lt;/code&gt;, mas pode ser qualquer outro de sua preferência. Só lembre de alterar o &lt;code&gt;type&lt;/code&gt; no arquivo &lt;code&gt;connection.ts&lt;/code&gt; caso mude de banco;
&lt;/li&gt;
&lt;/ul&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.1"&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;app&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="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.env&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;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="na"&gt;APP_PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${APP_PORT}&lt;/span&gt;
      &lt;span class="na"&gt;APP_PORT_INTERNAL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3333&lt;/span&gt;
      &lt;span class="na"&gt;DB_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${DB_HOST}&lt;/span&gt;
      &lt;span class="na"&gt;DB_PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5432&lt;/span&gt;
      &lt;span class="na"&gt;DB_USERNAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${DB_USERNAME}&lt;/span&gt;
      &lt;span class="na"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${DB_PASSWORD}&lt;/span&gt;
      &lt;span class="na"&gt;DB_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${DB_DATABASE}&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="s"&gt;${APP_PORT}:3333&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;database&lt;/span&gt;
  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.env&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;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${DB_DATABASE}&lt;/span&gt; 
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${DB_USERNAME}&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${DB_PASSWORD}&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="s"&gt;${DB_PORT}:5432&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ec.rating.data:/var/lib/postgresql/data"&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ec.rating.data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em &lt;code&gt;app&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Primeiro dizemos em qual diretório o &lt;code&gt;Dockerfile&lt;/code&gt; se encontra. Como está no mesmo do &lt;code&gt;docker-compose.yml&lt;/code&gt;, utilizamos &lt;code&gt;.&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;env_file&lt;/code&gt; irá ler o &lt;code&gt;.env&lt;/code&gt; e carregar os valores pra dentro do container. Usamos a sintaxe &lt;code&gt;${...}&lt;/code&gt; para obter esses valores;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;restart&lt;/code&gt; caso o container pare queremos que ele reinicie sem precisar de intervenção humana;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;environment&lt;/code&gt; passamos para a aplicação todas as variáveis de ambiente que ela precisará;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ports&lt;/code&gt; mapeamos a porta do nosso &lt;em&gt;host&lt;/em&gt; para dentro do container;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;depends_on&lt;/code&gt; para que o &lt;code&gt;app&lt;/code&gt; suba após o &lt;code&gt;database&lt;/code&gt;. Isso irá evitar o erro do &lt;code&gt;app&lt;/code&gt; subir primeiro e tentar conectar com o &lt;code&gt;database&lt;/code&gt; que ainda não existe;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Em &lt;code&gt;database&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;image&lt;/code&gt; base do &lt;code&gt;postgres&lt;/code&gt; disponível no DockerHub&lt;/li&gt;
&lt;li&gt;(...) mesma coisa do &lt;code&gt;app&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Como um container não mantêm estado precisamos mapear um diretório do &lt;code&gt;host&lt;/code&gt; para dentro do container. Fazemos isso através dos &lt;code&gt;volumes&lt;/code&gt;. Assim, independente de qual container esteja rodando, isso manterá os arquivos salvos já que ele sempre olhará para a mesma pasta. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quando criamos containers pelo &lt;code&gt;docker-compose&lt;/code&gt; eles fazem parte automaticamente da mesma &lt;code&gt;network&lt;/code&gt;. Dentro do &lt;code&gt;app&lt;/code&gt;, por exemplo, podemos fazer referência ao &lt;code&gt;database&lt;/code&gt; pelo seu &lt;em&gt;alias&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A imagem do &lt;code&gt;app&lt;/code&gt; não irá compilar a menos que você diga. Antes de mais nada rode &lt;code&gt;$ docker-compose build app&lt;/code&gt; para que a imagem seja criada. Feito isso é só rodar &lt;code&gt;$ docker-compose up&lt;/code&gt; e deve estar tudo funcionando :).&lt;/p&gt;

&lt;h3&gt;
  
  
  Testando os endpoints
&lt;/h3&gt;

&lt;p&gt;Eu costumo utilizar o &lt;a href="https://insomnia.rest/"&gt;Insomnia&lt;/a&gt; para fazer requisições http, mas qualquer um serve.&lt;/p&gt;

&lt;h4&gt;
  
  
  GET
&lt;/h4&gt;

&lt;p&gt;Utilizando a porta dentro do &lt;code&gt;.env&lt;/code&gt;, fazemos uma requisição GET para &lt;code&gt;http://localhost:$PORT/ratings&lt;/code&gt; e ele deve retornar um json com esta mesma estrutura:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;comment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;best console&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;buyer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bruce Wayne&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;product&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PS4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;comment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;xbox one is better&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;buyer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bruce Wayne&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;product&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PS4&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;h4&gt;
  
  
  POST
&lt;/h4&gt;

&lt;p&gt;Agora para criar um novo registro envie uma requisição POST para a mesma URL. Com um body nessa estrutura:&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="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;comment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;new rate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;productId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;buyerId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A resposta deve ser algo parecido com isso:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;buyer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fullName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bruce Wayne&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;product&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PS4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;comment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;new rate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  AWS
&lt;/h3&gt;

&lt;p&gt;Irei publicar este projeto na AWS, porém como estamos usando Docker, qualquer provedor irá servir e a mudança na publicação é mínima.&lt;/p&gt;

&lt;p&gt;Instale o &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/install-cliv1.html"&gt;AWS CLI&lt;/a&gt; na sua máquina, &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html"&gt;configure seu acesso pelo terminal&lt;/a&gt; e instale o &lt;a href="https://docs.docker.com/machine/install-machine/"&gt;docker-machine&lt;/a&gt;. Agora, se foi tudo configurado certo, rodamos &lt;code&gt;$ docker-machine create --driver amazonec2 aws01&lt;/code&gt; e isso irá criar e configurar uma máquina com tudo que precisamos para rodar os containers na AWS. Se rodarmos &lt;code&gt;$ docker-machine env aws01&lt;/code&gt; iremos ver alguns valores referentes a máquina criada. Na última linha terá um comando como este: &lt;code&gt;$ eval $(docker-machine env aws01)&lt;/code&gt;. Assim que rodá-lo o CLI do Docker &lt;strong&gt;irá referenciar esta máquina remota como o Host&lt;/strong&gt;, desta forma podemos rodar &lt;code&gt;$ docker-compose up -d&lt;/code&gt; e isso criará toda a aplicação e o banco de dados neste servidor. Feito isso é só liberar as portas no Dashboard da AWS e pronto. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Para voltar a referenciar sua máquina como &lt;em&gt;host&lt;/em&gt; no Docker rode &lt;code&gt;$ eval $(docker-machine -u)&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Com Docker conseguimos criar todo um ambiente de maneira automatizada e fazer o Deploy de maneira muito simples. O próximo passo seria criar um processo de CI/CD e fazer este deploy de maneira automática também.&lt;/p&gt;

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

&lt;p&gt;Vimos neste artigo a criação de uma API com Deno de ponta-a-ponta utilizando práticas de uma aplicação real.&lt;/p&gt;

&lt;p&gt;Dado esta experiência posso concluir que Deno é uma promessa para um futuro próximo ainda. Definitivamente não recomendo criar nenhuma aplicação para produção com ele! Mas como bons programadores que somos, é muito legal aprender sobre algo novo, testar e ver tudo funcionando no final. Quem sabe daqui 1 ou 2 anos estaremos com um ambiente estável e discutindo sobre novas features dele. Quem quiser contribuir com a comunidade, este é o melhor momento. &lt;/p&gt;

&lt;p&gt;Aprenda, teste e ensine.&lt;br&gt;
&lt;strong&gt;DEVELOPERS TOGETHER STRONG&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>deno</category>
      <category>typescript</category>
      <category>postgres</category>
      <category>docker</category>
    </item>
    <item>
      <title>Implementando Domain-Driven Design</title>
      <dc:creator>Guilherme Camargo</dc:creator>
      <pubDate>Wed, 22 Apr 2020 12:53:44 +0000</pubDate>
      <link>https://dev.to/guisfits/implementando-domain-driven-design-3d1h</link>
      <guid>https://dev.to/guisfits/implementando-domain-driven-design-3d1h</guid>
      <description>&lt;p&gt;Após vermos os conceitos do DDD com os &lt;a href="https://dev.to/guisfits/easycommerce-01-introducao-ao-ddd-kik"&gt;Strategic Patterns&lt;/a&gt;, está na hora de ver algum código. Neste artigo abordarei os Tactical Patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tactical Patterns
&lt;/h2&gt;

&lt;p&gt;O objetivo dos &lt;strong&gt;Tactical Patterns&lt;/strong&gt; é gerenciar a complexidade e garantir a expressividade do &lt;em&gt;Domain Model&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Eric Evans agrupou alguns &lt;strong&gt;Design Patterns (Building Blocks)&lt;/strong&gt; em seu livro, que são um conjunto de boas práticas em torno dos princípios de OOP. Todos esses patterns já existiam antes de Evans os agrupar e não são exclusivos do DDD, porém Evans conseguiu consolidá-los de tal maneira que se tornaram uma ferramenta poderosa quando queremos criar um design rico e expressivo em domínios complexos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Entity
&lt;/h3&gt;

&lt;p&gt;Uma &lt;em&gt;Entity&lt;/em&gt; é um objeto que mantém um ciclo de vida independente do seu estado atual. Seus atributos podem mudar, porém podemos sempre identificá-las por algum campo específico, como um número inteiro ou um &lt;em&gt;GUID&lt;/em&gt;, por exemplo.&lt;/p&gt;

&lt;p&gt;Vamos pegar de exemplo uma cesta de compras de um e-commerce. Após criarmos uma &lt;em&gt;Entity&lt;/em&gt; &lt;strong&gt;Basket&lt;/strong&gt; ela naturalmente passará por mutação, o valor total, quantidade de itens e outros campos podem receber outros valores, porém sempre saberemos diferenciá-la pelo seu &lt;strong&gt;Id&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Em uma modelagem &lt;em&gt;Table Oriented&lt;/em&gt;, onde cria-se classes com objetivo de representar tabelas em um banco relacional, deixa-se de considerar sua representatividade para o domínio, onde essas &lt;strong&gt;classes anêmicas&lt;/strong&gt; são simplesmente sacolas de dados.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Você deve ser capaz de criar todo o seu domínio e testá-lo sem sequer saber qual banco de dados irá usar, seja relacional ou NoSQL.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A &lt;em&gt;Entity&lt;/em&gt; é uma das peças fundamentais no nosso &lt;em&gt;Domain Model&lt;/em&gt; e devemos criá-la exclusivamente para satisfazê-lo. Ela é composta não apenas por atributos primitivos (int, float, string...), mas também por outras &lt;em&gt;Entities&lt;/em&gt; e objetos complexos - &lt;em&gt;Value Objects&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;É importante mantermos sua consistência. Em linguagens orientadas a objeto devemos tornar seus atributos privados de modo a blindá-los de modificações externas. Isso vai garantir que toda a mudança de estado passe por um método que aplicará possíveis regras.&lt;/p&gt;

&lt;p&gt;A própria &lt;em&gt;Entity&lt;/em&gt; deve saber se construir. É uma má-pratica não ter um construtor neste caso, pois se deixamos classes externas criar objetos sem considerar suas regras, eventualmente iremos ter objetos inconsistentes.&lt;/p&gt;

&lt;p&gt;Quando temos comportamento correspondente a uma &lt;em&gt;Entity&lt;/em&gt;, quem melhor para tratá-los do que ela mesma? É comum em modelagens anêmicas deixar todo o comportamento para classes externas, porém acabamos somente quebrando a classe em N pedaços e dividindo sua responsabilidade. Se algo do mundo real tem estado e comportamento, uma &lt;em&gt;Entity&lt;/em&gt; deve representá-lo fielmente.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Felwf8v4lhsa0nclcmpyi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Felwf8v4lhsa0nclcmpyi.png" alt="entity"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Value Object
&lt;/h3&gt;

&lt;p&gt;Diferentemente da &lt;em&gt;Entity&lt;/em&gt;, um &lt;em&gt;Value Object&lt;/em&gt; é definido por seus atributos.&lt;/p&gt;

&lt;p&gt;Tome o clássico exemplo da classe &lt;strong&gt;Money&lt;/strong&gt;. O que difere duas instâncias com o mesmo valor? Nada! Eles não mantêm um ciclo de vida, sendo criados, utilizados e descartados! Também são plenamente substituíveis por outro objeto do mesmo tipo e valor.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Value objects&lt;/em&gt; são imutáveis por definição. Assim como no mundo real você não consegue transformar R$ 5,00 em R$ 50,00, &lt;em&gt;Value Objects&lt;/em&gt; também não permitem esta mudança. Para conseguir um novo valor devemos criar uma nova instância de seu tipo, nunca alterar seus atributos internos.&lt;/p&gt;

&lt;p&gt;Uma &lt;em&gt;Entity&lt;/em&gt; pode ser composta por N &lt;em&gt;Value Objects&lt;/em&gt;. Como &lt;em&gt;Value Objects&lt;/em&gt; não mantêm estado, não temos como identificá-los no banco de dados, portanto devemos persisti-lo junto a &lt;em&gt;Entity&lt;/em&gt;, nunca separado.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Em bancos de dados orientado a documentos podemos salvá-lo dentro do mesmo objeto. Em bancos de dados relacionais podemos usar um ORM para mapear esses objetos para colunas específicas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftdij33xtsalizcwsbe4e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftdij33xtsalizcwsbe4e.png" alt="value-object"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Domain-Service
&lt;/h3&gt;

&lt;p&gt;Quando temos um comportamento não atrelado a uma &lt;em&gt;Entity&lt;/em&gt; ou &lt;em&gt;Value Object&lt;/em&gt;, podemos representá-lo como um &lt;em&gt;Domain Service&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Domain Service&lt;/em&gt; tem as seguintes características:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Não mantêm estado&lt;/li&gt;
&lt;li&gt;Não tem rastreabilidade&lt;/li&gt;
&lt;li&gt;Podem receber &lt;em&gt;Entities&lt;/em&gt; e &lt;em&gt;Value Objects&lt;/em&gt; como parâmetro&lt;/li&gt;
&lt;li&gt;Podem ter dependências de interfaces para serviços externos&lt;/li&gt;
&lt;li&gt;Executam alguma regra de negócio.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tome como exemplo o cálculo de taxa de envio de um pedido. Ele deve considerar os itens do carrinho, o peso de cada item e a distância do endereço de entrega. Logo, percebemos que toda essa lógica não se encaixa em nenhuma &lt;em&gt;Entity&lt;/em&gt; ou &lt;em&gt;Value Object&lt;/em&gt;. Um &lt;em&gt;Domain Service&lt;/em&gt; é perfeito neste caso.&lt;/p&gt;

&lt;p&gt;É importante mantermos a &lt;em&gt;Ubiquitous Language&lt;/em&gt; sempre em mente e aplicá-la aqui também, tanto no nome da classe e funções, quanto internamente - em nome de variáveis, por exemplo. Você pode pedir para uma pessoa de negócio explicar toda a regra e traduzir esse entendimento para o código. Assim se algo estiver faltando você facilmente conseguirá descrever o algoritmo para o &lt;em&gt;domain expert&lt;/em&gt; e receber um feedback de possíveis inconsistências.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy6d6a68ak5qlukvot8ja.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy6d6a68ak5qlukvot8ja.png" alt="domain-service"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Aggregate
&lt;/h3&gt;

&lt;p&gt;Para expressar uma ideia no código é comum ter uma árvore de classes que se relacionem e possuem dependências uma da outra. Porém, conforme o &lt;em&gt;Domain Model&lt;/em&gt; se expande esta árvore acaba se tornando muito extensa e com várias ramificações. Isso dificultará seu carregamento do banco de dados, suas invariâncias ao fazer alterações e problemas de concorrência.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwfwbjtkcl2f9xpb6f0vg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwfwbjtkcl2f9xpb6f0vg.png" alt="Aggregate-1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Com &lt;em&gt;Aggregates&lt;/em&gt; conseguimos diminuir a complexidade de objetos grandes para pequenos grupos de classes que devem ter operações atômicas. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Uma operação atômica é uma ação que ocorre completamente independente de outro processo. Uma &lt;em&gt;transaction&lt;/em&gt; num banco de dados relacional segue esse princípio. Assim que você inicia uma &lt;em&gt;transaction&lt;/em&gt;, nenhum outro processo poderá ler ou gravar um novo valor até que o processo anterior seja finalizado, desta forma se garante a consistência da operação e dos dados.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Um &lt;em&gt;Aggregate&lt;/em&gt; se comporta como uma única unidade em memória, tendo sempre uma &lt;em&gt;Entity&lt;/em&gt; principal que será o &lt;em&gt;Aggregate Root&lt;/em&gt; e a partir dela teremos acesso a outras &lt;em&gt;Entities&lt;/em&gt; e &lt;em&gt;Value Objects&lt;/em&gt;. &lt;em&gt;Aggregates&lt;/em&gt; podem se relacionar mantendo o &lt;strong&gt;Id&lt;/strong&gt; de outro &lt;em&gt;Aggregate&lt;/em&gt; em seus atributos, mas nunca uma referência para outro objeto &lt;em&gt;Aggregate&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Essa divisão deve seguir os conceitos do domínio e não apenas agrupar dados. Pense em suas invariâncias. Um &lt;strong&gt;Address&lt;/strong&gt; só pode ser alterado se soubermos a quem ele pertence, então não faz sentido &lt;strong&gt;Address&lt;/strong&gt; ser um objeto isolado já que ele está fortemente acoplado com &lt;strong&gt;Customer&lt;/strong&gt;. Por sua vez, &lt;strong&gt;Customer&lt;/strong&gt; é uma &lt;em&gt;Entity&lt;/em&gt; forte, dado que conseguimos outras informações através dela. Neste cenário faz sentido termos um &lt;em&gt;Aggregate&lt;/em&gt; chamado &lt;strong&gt;Customers&lt;/strong&gt;, sendo a &lt;em&gt;Entity&lt;/em&gt; &lt;strong&gt;Customer&lt;/strong&gt; seu &lt;em&gt;Aggregate Root&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7u11rynz5r4498dym11v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7u11rynz5r4498dym11v.png" alt="Aggregate-2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Em bancos orientado a documentos temos a facilidade de poder persistir um Aggregate por documento e obtê-lo de uma única vez.&lt;/p&gt;
&lt;/blockquote&gt;

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

FakeCommerce.Store.Shopping.Domain
├── Baskets
│   ├── Basket.cs
│   ├── BasketItem.cs
│   └── Coupon.cs
├── Customers
│   ├── Address.cs
│   ├── CreditCart.cs
│   └── Customer.cs
└── Products
    ├── Price.cs
    ├── Product.cs
    └── Size.cs


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Factory
&lt;/h3&gt;

&lt;p&gt;Se um &lt;em&gt;Aggregate&lt;/em&gt; é suficientemente complexo para ser construído podemos usar o pattern &lt;em&gt;Factory&lt;/em&gt;. Ele é um dos patterns originais do &lt;a href="https://pt.wikipedia.org/wiki/Padr%C3%A3o_de_projeto_de_software#Padr%C3%B5es_GoF_('Gang_of_Four')" rel="noopener noreferrer"&gt;GOF&lt;/a&gt;. Seu objetivo é criar objetos respeitando suas invariâncias, ou seja, ele só criará objetos que respeitem certas regras e estejam em estado válido.&lt;/p&gt;

&lt;p&gt;Por padrão, devemos usar o método construtor presente em muitas linguagens. Uma &lt;em&gt;Factory&lt;/em&gt; é útil somente em ocasiões em que o construtor fica sobrecarregado com regras, ou quando temos mais de uma maneira de construir o objeto.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcm4qxsxix3k9iipps34f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcm4qxsxix3k9iipps34f.png" alt="factory"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Repository
&lt;/h3&gt;

&lt;p&gt;Agora que temos os objetos organizados por &lt;em&gt;Aggregates&lt;/em&gt; precisamos de um meio para persistí-los e hidratá-los. O pattern &lt;em&gt;Repository&lt;/em&gt; é um dos mais conhecidos e seu objetivo é abstrair o acesso a dados da camada de domínio. Ele se comporta como uma coleção de dados em memória. Para quem está consumindo é transparente, além de não criar acoplamento com o meio de persistência.&lt;/p&gt;

&lt;p&gt;Devemos ter um &lt;em&gt;Repository&lt;/em&gt; por &lt;em&gt;Aggregate&lt;/em&gt;. Como o &lt;em&gt;Aggregate&lt;/em&gt; se comporta como uma unidade, não faz sentido ter um &lt;em&gt;Repository&lt;/em&gt; para cada classe dele, faz mais sentido persistir e hidratar esses objetos juntos.&lt;/p&gt;

&lt;p&gt;O uso de &lt;em&gt;Repositories&lt;/em&gt; acaba sendo extrapolado em alguns casos. Ele é bastante útil quando precisamos hidratar os dados na camada de domínio e para reaproveitar operações comuns, porém seu uso não é obrigatório. Se você precisa extrair um relatório do sistema ou obter dados, formatar e enviar através de uma API, por exemplo, um &lt;em&gt;Repository&lt;/em&gt; acaba não ajudando muito, pois não se torna tão flexível. É importante mantermos o senso crítico e somente usá-lo quando trazer algum benefício.&lt;/p&gt;

&lt;p&gt;Para usá-lo adequadamente basta criar uma interface na pasta do &lt;em&gt;Aggregate&lt;/em&gt; e definir os métodos. Lembre-se de usar a &lt;em&gt;Ubiquitous Language&lt;/em&gt; e evitar o nome do pattern na camada de domínio. Eu geralmente crio as interfaces com o nome do &lt;em&gt;Aggregate&lt;/em&gt; no plural, &lt;strong&gt;ICustomers&lt;/strong&gt;, por exemplo, assim indico o seu comportamento (uma coleção em memória) sem sujar a linguagem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbj7xzsrv78kx26tlujgf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbj7xzsrv78kx26tlujgf.png" alt="repository"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora, com &lt;em&gt;Dependency Inversion&lt;/em&gt;, podemos receber esta interface pelo construtor sem conhecer sua implementação que está na camada de infraestrutura.&lt;/p&gt;
&lt;h3&gt;
  
  
  Domain-Event
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Domain Events&lt;/em&gt; são muito úteis quando queremos propagar ações ocorridas dentro do &lt;em&gt;Domain Model&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Esse pattern se dá na criação de uma classe &lt;em&gt;POCO&lt;/em&gt; com os dados que queremos propagar. Todo o &lt;em&gt;Domain Event&lt;/em&gt; lançado já aconteceu, refletindo o passado. &lt;em&gt;Events&lt;/em&gt; são imutáveis, já que uma vez que este evento ocorreu não tem como voltar e alterá-lo. Eles seguem o princípio &lt;em&gt;Fire and Forget&lt;/em&gt;, já que uma vez lançado não temos mais controle de quem irá receber, podendo ser uma ou mais classes, devido a isso também eles não possuem nenhum retorno.&lt;/p&gt;

&lt;p&gt;Temos algumas maneiras de implementá-lo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Se o &lt;em&gt;Domain Event&lt;/em&gt; será somente de uso interno - dentro do mesmo &lt;em&gt;Bounded Context&lt;/em&gt;, podemos usar uma biblioteca como &lt;strong&gt;MediatR&lt;/strong&gt;. Ela já possui uma interface chamada &lt;strong&gt;INotification&lt;/strong&gt; que será aplicada no &lt;em&gt;Domain Event&lt;/em&gt; e outra &lt;strong&gt;INoficationHandler&lt;/strong&gt; que será aplicada em quem esta ouvindo este evento. Assim toda vez que você disparar um novo &lt;em&gt;Domain Event&lt;/em&gt; todos os &lt;em&gt;Handlers&lt;/em&gt; irão ser chamados imediatamente, pois tudo isso acontece em memória dentro do mesmo processo. &lt;/li&gt;
&lt;li&gt;Se o &lt;em&gt;Domain Event&lt;/em&gt; se propaga para outros &lt;em&gt;Bounded Contexts&lt;/em&gt; podemos usar uma solução mais robusta, como o &lt;strong&gt;RabbitMQ&lt;/strong&gt;, por exemplo. Com ele não precisamos criamos acoplamento entre os &lt;em&gt;Bounded Contexts&lt;/em&gt;, e seus Handlers podem ficar em processos separados, aumentando a escalabilidade da aplicação.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxwbf0jigenvbnc0dxzh6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxwbf0jigenvbnc0dxzh6.png" alt="domain event"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9zgrvgeu3d6ii3o5ue1p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9zgrvgeu3d6ii3o5ue1p.png" alt="domain event handler"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Modules
&lt;/h3&gt;

&lt;p&gt;E por último, mas não menos importante, vamos falar de &lt;em&gt;Modules&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Para criar &lt;em&gt;Modules&lt;/em&gt; em &lt;code&gt;C#&lt;/code&gt; temos os &lt;code&gt;namespace&lt;/code&gt;, que nada mais são do que um caminho virtual para as classes. Temos também os arquivos de extensão &lt;code&gt;.csproj&lt;/code&gt;, esses servem para separar os arquivos fisicamente e gerenciar suas dependências. Outras linguagens tem conceitos parecidos - como &lt;code&gt;packages&lt;/code&gt; em &lt;code&gt;Java&lt;/code&gt; - mas só o caminho real já pode ser o suficiente na maioria dos casos.&lt;/p&gt;

&lt;p&gt;Com o uso de &lt;em&gt;Modules&lt;/em&gt; conseguimos manter a organização do projeto de maneira consistente e respeitar a estrutura da &lt;em&gt;Ubiquitous Language&lt;/em&gt;. Esta estrutura deve nos dizer sua intenção e falar a linguagem do negócio ao mesmo tempo. Essa organização, entre outras coisas, ajuda:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A entender assuntos relacionados e manter assuntos distintos fisicamente separados.&lt;/li&gt;
&lt;li&gt;Na manutenção, pois quando você precisar mexer em uma área saberá exatamente onde procurar.&lt;/li&gt;
&lt;li&gt;A novos desenvolvedores entender o projeto e saber onde devem ou não mexer.&lt;/li&gt;
&lt;li&gt;A evitar conflitos de classes com o mesmo nome.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Modules&lt;/em&gt; são usados para decompor o &lt;em&gt;Domain Model&lt;/em&gt;. Um domínio grande terá múltiplos &lt;em&gt;Bounded Contexts&lt;/em&gt; e esses terão múltiplos conceitos. Podemos considerar esses conceitos como os &lt;em&gt;Modules&lt;/em&gt;. Por exemplo, quando o &lt;em&gt;domain expert&lt;/em&gt; da &lt;strong&gt;Store&lt;/strong&gt; fala sobre &lt;strong&gt;Shopping&lt;/strong&gt;, espera-se que todo o código relacionado a este assunto esteja em um namespace como &lt;code&gt;{CompanyName}.Store.Shopping&lt;/code&gt;. &lt;em&gt;Modules&lt;/em&gt; se mantém entre o &lt;em&gt;Bounded Context&lt;/em&gt; e os &lt;em&gt;Aggregates&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Não há uma regra dizendo como você deve arquitetar seu projeto, isso é muito subjetivo e tem N fatores que influenciam, mas de modo a ilustrar um exemplo seguindo a divisão em camadas proposta por alguns autores, podemos ter algo parecido com isso:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

└── FakeCommerce.Store
    └── FakeCommerce.Store.Shopping
        ├── FakeCommerce.Store.Shopping.Application
        ├── FakeCommerce.Store.Shopping.Domain
        ├── FakeCommerce.Store.Shopping.Integration
        └── FakeCommerce.Store.Shopping.Persistence


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application&lt;/strong&gt; onde ficará os casos de uso e regras da aplicação.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain&lt;/strong&gt; terá os &lt;em&gt;Aggregates&lt;/em&gt; e as regras de negócio.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration&lt;/strong&gt; será responsável pela comunicação com outros &lt;em&gt;Bounded Contexts&lt;/em&gt; (Anti-Corruption Layer) e serviços externos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistence&lt;/strong&gt; cuidará da infraestrutura do banco de dados e terá a implementação dos &lt;em&gt;Repositories&lt;/em&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Desta forma, garantimos que o domínio fique isolado do restante da aplicação e que só tenha classes com regras de negócio, sem se preocupar com detalhes de implementação que irão ficar em outras camadas.&lt;/p&gt;

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

&lt;p&gt;Os &lt;em&gt;Building Blocks&lt;/em&gt; são patterns poderosos para nos auxiliar a construir um &lt;em&gt;Domain Model&lt;/em&gt; que satisfaça as necessidades do &lt;em&gt;Domain&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Seja pragmático no seu uso, saber não é dever. Cada pattern tem sua utilidade na construção do &lt;em&gt;Domain Model&lt;/em&gt; e eles devem ser usados à medida que as necessidades surgem, não antes. Deixe o domínio emergir naturalmente, já que a tendência é começar simples e ir ficando complexo com o tempo. Essas ocasiões são perfeitas para rever o que foi implementado e refatorar o que for necessário.&lt;/p&gt;

&lt;p&gt;Pratique! Criei um projeto para exercitar esses patterns e aproveite para se aprofundar mais em cada um conforme as dúvidas surgirem. É nessas horas que você realmente entende o problema que cada um resolve e o seu valor como pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  Referências
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com.br/Patterns-Principles-Practices-Domain-Driven-English-ebook/dp/B00XLYUA0W/ref=sr_1_1?__mk_pt_BR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;amp;keywords=Patterns%2C+Principles%2C+and+Practices+of+Domain-Driven+Design&amp;amp;qid=1587221702&amp;amp;s=digital-text&amp;amp;sr=1-1" rel="noopener noreferrer"&gt;Patterns, Principles, and Practices of Domain-Driven Design&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://culttt.com/2014/12/10/modules-domain-driven-design/" rel="noopener noreferrer"&gt;What are Modules in Domain Driven Design?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ddd</category>
      <category>designpattern</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Entendendo Domain-Driven Design</title>
      <dc:creator>Guilherme Camargo</dc:creator>
      <pubDate>Fri, 13 Mar 2020 01:24:22 +0000</pubDate>
      <link>https://dev.to/guisfits/easycommerce-01-introducao-ao-ddd-kik</link>
      <guid>https://dev.to/guisfits/easycommerce-01-introducao-ao-ddd-kik</guid>
      <description>&lt;p&gt;Um dos principais conceitos que aprendi e mudou a forma como escrevo software foi Domain-Driven Design. Ele me trouxe outra visão de como abordar problemas, como criar soluções mais alinhadas com a área de negócio e com um melhor design. Neste artigo irei revisá-lo e compartilhar o meu conhecimento sobre os seus conceitos.&lt;/p&gt;

&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;h2&gt;
  
  
  O que é, onde aplicar e benefícios
&lt;/h2&gt;

&lt;p&gt;Domain-Driven Design (DDD) é uma metodologia de desenvolvimento de software. Originou-se em 2003 por Eric Evans em seu conhecido livro &lt;em&gt;Domain-Driven Design: Tackling Complexity in the Heart of Software&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Ele é, acima de tudo, uma metodologia que habilita o desenvolvimento de software de alta complexidade de negócio de maneira efetiva. Através da sua filosofia, práticas e patterns, DDD nos permite gerar valor, reduzir custos e facilitar a evolução de aplicações que poderiam facilmente terminar de maneira trágica. Ele nos apresenta maneiras de modelar essas aplicações de tal forma que fique muito próxima à área de problema que estamos resolvendo, isso habilita a equipe técnica a desenvolver tais sistemas de maneira consistente e saudável.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que não é, onde evitar e malefícios
&lt;/h2&gt;

&lt;p&gt;Devemos ter ciência que quando falamos exclusivamente de arquitetura de software ou design patterns (Repositories, Entities, Services, Factories, etc) não estamos falando sobre DDD necessariamente. A parte prática com &lt;em&gt;Building Blocks&lt;/em&gt; e Design de Arquitetura são importantes também, sem dúvida, porém elas não se sustentam sozinhas e não são o ponto central do DDD, estão lá simplesmente para nos auxiliar. Podemos ter um sistema que implementa todos os design patterns sugeridos, mas não atende o negócio. Por outro lado podemos ter um design mais simplista, mas que esteja totalmente alinhado ao domínio. DDD não exige que nenhum design pattern seja implementado, a única coisa exigida é que nosso domínio esteja isolado do restante da aplicação para que possamos focar nas regras de negócio e não misturar esses conceitos com problemas técnicos, além disso, DDD não está restrito somente ao paradigma de programação orientada a objetos. Concluímos então que &lt;strong&gt;não existe receita de bolo ou template padrão para implementá-lo&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Não devemos considerar DDD em aplicações onde não há complexidade de negócio. Tais aplicações não iriam se beneficiar do que nos é apresentado. DDD somente traria complexidade desnecessária e dificuldade em sua execução. Também devemos evitar seu uso onde não temos pessoas qualificadas para aplicar o conhecimento e as práticas requeridas, nem onde não temos contato direto com pessoas de negócio.&lt;/p&gt;

&lt;h1&gt;
  
  
  Problem Space
&lt;/h1&gt;

&lt;p&gt;Quando falamos de &lt;em&gt;Problem Space&lt;/em&gt; estamos nos referindo a área de negócio na qual o cliente está inserido e o que nosso software pretende resolver. Aqui aprendemos a gerenciar o problema e a destila-lo a fim de reduzir a sua complexidade.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq9aa24sp7rs72eakd6a3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq9aa24sp7rs72eakd6a3.png" alt="Problem Space"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Domain
&lt;/h2&gt;

&lt;p&gt;O domínio é realidade do negócio, se refere a área de conhecimento e atividade na qual a organização e as pessoas estão inseridas. Envolve todas as regras, comportamentos, processos e entendimentos que lá habitam. Domínio é onde as pessoas de negócio vivem e na qual nós, desenvolvedores, não temos interferência.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Foiw26yf4vqmj6irjrxs9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Foiw26yf4vqmj6irjrxs9.png" alt="Domain"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Subdomains
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fh8vbu3rec37s8091pig0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fh8vbu3rec37s8091pig0.png" alt="Subdomains"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Subdomain se dá no processo de decompor o nosso domínio em três categorias:&lt;/p&gt;

&lt;h3&gt;
  
  
  Core
&lt;/h3&gt;

&lt;p&gt;É o que gera maior valor, o motivo da organização existir, o diferencial entre os seus concorrentes, é onde os 20% geram 80% dos resultados. O &lt;em&gt;Core Domain&lt;/em&gt; é onde se deve gastar maior parte do tempo e recursos. Onde os desenvolvedores mais experientes devem trabalhar e onde devemos criar o design mais robusto.&lt;/p&gt;

&lt;p&gt;Em um projeto de e-commerce, por exemplo, o &lt;em&gt;Core Domain&lt;/em&gt; pode ser &lt;strong&gt;Sales&lt;/strong&gt;. Isso não quer dizer que todos os e-commerces possuem o mesmo Core. Se um e-commerce se propõe a fazer entregas em até 24 horas, o &lt;em&gt;Core Domain&lt;/em&gt; será &lt;strong&gt;Shipping&lt;/strong&gt;, se outro e-commerce se destaca por ser o mais barato entre a concorrência, seu &lt;em&gt;Core Domain&lt;/em&gt; será &lt;strong&gt;Pricing&lt;/strong&gt;, então tenha em mente que os &lt;em&gt;subdomains&lt;/em&gt; serão diferentes de empresa para empresa. Nosso papel aqui é mapear a realidade do negócio existente, não tentar encaixar modelos preconcebidos nele.&lt;/p&gt;

&lt;h3&gt;
  
  
  Supporting
&lt;/h3&gt;

&lt;p&gt;Ele é o que habilita o &lt;em&gt;Core Domain&lt;/em&gt; exercer seu papel, sem ele a organização não iria funcionar e ele precisa de um certo nível de customização, porém não possui vantagem competitiva. Ele é importante, mas não devemos gastar mais esforços do que o necessário. Aqui feito é bem feito!&lt;/p&gt;

&lt;p&gt;Olhando nosso exemplo, os items em amarelo são áreas que sem elas o sistema não iria funcionar. Não conseguimos vender um produto sem um meio de pagamento, sem estoque no armazém, sem uma boa logística, etc. Todas essas áreas servem de auxílio para que o &lt;em&gt;Core&lt;/em&gt; funcione adequadamente.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generic
&lt;/h3&gt;

&lt;p&gt;Não são de maior preocupação e não possui relação exclusiva com nosso &lt;em&gt;Core Domain&lt;/em&gt;. Caso seja criada uma solução interna devemos fazer com que ela simplesmente funcione, nada mais, provavelmente delegar para desenvolvedores menos experientes. Outra alternativa seria contratar uma solução de terceiros.&lt;/p&gt;

&lt;p&gt;As nossas caixinhas em vermelho representam o que é genérico para nós. Como o nosso foco é a venda temos que deixar algumas coisas de lado. Aceitamos que existem soluções de recomendações muito melhores do que podemos criar, podemos contratar uma dessas soluções através de SaaS. Também não é nosso foco customizar a experiência de cada cliente, só precisamos de alguns dados básicos - uma API com alguns métodos CRUD resolverá o nosso problema.&lt;/p&gt;

&lt;h1&gt;
  
  
  Solution Space
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Solution Space&lt;/em&gt; se refere ao &lt;strong&gt;como&lt;/strong&gt; iremos resolver o &lt;em&gt;Problem Space&lt;/em&gt;. Envolve práticas e patterns a fim de criar uma solução efetiva.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0yjugtht71246mklkqrv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0yjugtht71246mklkqrv.png" alt="Solution Space"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Domain Models
&lt;/h2&gt;

&lt;p&gt;O que é exatamente um "Modelo"? Segundo o &lt;a href="https://dicionariocriativo.com.br/significado/modelo" rel="noopener noreferrer"&gt;Dicionário Criativo&lt;/a&gt; temos a seguinte definição:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Representação abstrata de um fenômeno, capaz de captar as características formais ou funcionais do objeto de estudo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Podemos entender então que um modelo nada mais é do que uma visão/imagem que temos de um conceito. Trazendo para nosso cenário seria criar abstrações que representam nosso domínio em um determinado contexto. Ao fazer isso poderemos discutir com mais propriedade os termos e obter das pessoas de negócio conceitos subentendidos. Ele é fruto da colaboração. Sua maior utilidade se dá no entendimento compartilhado das regras e processos. Em resumo, &lt;em&gt;Domain Model&lt;/em&gt; é a implementação de uma solução para o &lt;em&gt;Domain&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fadti64xjhobxtxt5kao2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fadti64xjhobxtxt5kao2.png" alt="Domain Model"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Analysis Model
&lt;/h3&gt;

&lt;p&gt;Durante as reuniões irão surgir ideias que podemos traduzir para diagramas (UML), onde desenvolvedores e pessoas de negócio possam entender e colaborar sobre os processos discutidos, estes são conhecidos como &lt;em&gt;analysis model&lt;/em&gt;. Eles não são focados no aspecto técnico e não devem ter detalhes de implementação.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Model
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Code Model&lt;/em&gt; é a implementação dos &lt;em&gt;Analysis Model&lt;/em&gt;. Eles são criados utilizando os conceitos aprendidos no modelo anterior. Todo o &lt;em&gt;Code Model&lt;/em&gt; deve servir apenas e exclusivamente ao nosso domínio, não devemos utilizar aqui nomes de patterns como Repository, Factory, Service, Manager, etc - isso somente iria gerar ruído na comunicação. Ao invés disso devemos utilizar a &lt;em&gt;Ubiquitous Language&lt;/em&gt; na implementação.&lt;/p&gt;

&lt;h3&gt;
  
  
  Model-Driven Design
&lt;/h3&gt;

&lt;p&gt;É o processo de sincronização entre o &lt;em&gt;analysis model&lt;/em&gt; com &lt;em&gt;code model&lt;/em&gt;. Em um cenário ideal ambos são traduzíveis de 1:1, para isso precisamos de uma implementação livre de detalhes técnicos e um &lt;em&gt;analysis model&lt;/em&gt; que não seja tão abstrato. Durante esse processo precisamos analisar se os jargões foram modelados de forma explícita para garantir que os mesmo termos usados nas discussões estejam na implementação. Durante a implementação do &lt;em&gt;code model&lt;/em&gt; a equipe técnica poderá identificar falhas de conceitos e regras, isso permite trazer novas reflexões durante reuniões e refinar o processo de maneira iterativa, o que levará na atualização do &lt;em&gt;analysis model&lt;/em&gt; inicial. Desta forma isso gera um processo de melhoria contínua na qual &lt;em&gt;analysis model&lt;/em&gt; e &lt;em&gt;code model&lt;/em&gt; se retroalimentam.&lt;/p&gt;

&lt;h2&gt;
  
  
  Strategic Patterns
&lt;/h2&gt;

&lt;p&gt;Os &lt;em&gt;Strategic Patterns&lt;/em&gt; nos ajudam a destilar o &lt;em&gt;Problem Space&lt;/em&gt; e arquitetar a aplicação guiada pelo domínio.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ubiquitous Language
&lt;/h3&gt;

&lt;p&gt;Entende-se como onipresente aquilo que está em todos os lugares. Para conseguirmos ter uma comunicação efetiva com pessoas de domínio é essencial falarmos a mesma língua. Ubiquitous Language é criada entre a colaboração da equipe técnica e pessoas de negócio, ela deve ser falada e escrita durante conversas, desenhos e implementações. Ela é dividida entre os &lt;em&gt;Bounded Context&lt;/em&gt;. Esta linguagem é um artefato vivo, terá evoluções e refinamentos. É importante deixá-la de forma explícita para que todos entendam os seus termos, talvez manter um glossário ou outra documentação em que todos tenham acesso.&lt;/p&gt;

&lt;h4&gt;
  
  
  Inglês ou Português?
&lt;/h4&gt;

&lt;p&gt;É prática comum, até recomendável, que nosso código seja escrito em inglês, porém isso entra em conflito com a &lt;em&gt;Ubiquitous Language&lt;/em&gt;. Quando estamos trabalhando com domínio complexo devemos deixar nosso código com o idioma falado para não perder a relação com as pessoas de negócio.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bounded Context
&lt;/h3&gt;

&lt;p&gt;Após identificar nossos &lt;em&gt;subdomains&lt;/em&gt; e ter uma linguagem compartilhada com pessoas de negócio iremos perceber que os termos utilizados tendem a ter mais de um significado para pessoas/processos/áreas diferentes. Um &lt;strong&gt;Product&lt;/strong&gt; para o contexto &lt;strong&gt;Sales&lt;/strong&gt; significa uma coisa e para o contexto &lt;strong&gt;Shipping&lt;/strong&gt; outra. Ao invés de tentar criar um modelo único, aka &lt;a href="https://en.wikipedia.org/wiki/God_object" rel="noopener noreferrer"&gt;God Object&lt;/a&gt;, a ideia do &lt;em&gt;Bounded Context&lt;/em&gt; é criar divisões entre essa linguagem, onde cada um tem o seu modelo que representa uma abstração do problema, isso impede que os conceitos se misturem e que nosso software acabe se tornando um &lt;a href="https://thedomaindrivendesign.io/big-ball-of-mud/" rel="noopener noreferrer"&gt;BBoM&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fij5our7tyg51k1czrlfk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fij5our7tyg51k1czrlfk.png" alt="Contexts"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Um &lt;em&gt;Subdomain&lt;/em&gt; é algo abstrato/conceitual no qual podemos apenas discutir. Um &lt;em&gt;Bounded Context&lt;/em&gt;, por outro lado, é um artefato que traduz esses conceitos para o software. Em um mundo perfeito todos nossos Subdomains seriam traduzíveis para um &lt;em&gt;Bounded Context&lt;/em&gt; correspondente, infelizmente a realidade pode não ser tão generosa em alguns casos. Podemos ter N &lt;em&gt;Bounded Contexts&lt;/em&gt; para satisfazer um &lt;em&gt;Subdomain&lt;/em&gt;, o que ira guiar a divisão neste caso é a &lt;em&gt;Ubiqutious Language&lt;/em&gt;. Devemos ficar atentos somente quando um &lt;em&gt;Bounded Context&lt;/em&gt; tende a atender mais de um &lt;em&gt;Subdomain&lt;/em&gt;, isso fere o &lt;a href="https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html" rel="noopener noreferrer"&gt;&lt;em&gt;Single Responsibility Principle&lt;/em&gt;&lt;/a&gt;, pois um &lt;em&gt;B.C.&lt;/em&gt; terá mais de um motivo para ser alterado.&lt;/p&gt;

&lt;p&gt;Seguindo os &lt;em&gt;Subdomains&lt;/em&gt; propostos, vamos pensar na organização do projeto. Dentro de &lt;strong&gt;Customer&lt;/strong&gt; podemos ter um &lt;em&gt;Bounded Context&lt;/em&gt; chamado &lt;strong&gt;User&lt;/strong&gt; que irá tratar do Nome, Endereços, Formas de Pagamento, Avatar, etc; e outro &lt;em&gt;Bounded Context&lt;/em&gt; de &lt;strong&gt;Account&lt;/strong&gt; contendo E-mail, Password, Roles, Claims, etc. E em &lt;strong&gt;Sales&lt;/strong&gt; temos &lt;strong&gt;Orders&lt;/strong&gt;, &lt;strong&gt;Pricing&lt;/strong&gt; e &lt;strong&gt;ShoppingCart&lt;/strong&gt;, para os demais acredito que um &lt;strong&gt;Bounded Context&lt;/strong&gt; para cada irá servir.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;App
  ├── Billing
  ├── Catalog
  ├── Customers
  │ ├── Account
  │ └── User
  ├── Sales
  │ ├── Orders
  │ ├── Pricing
  │ └── ShoppingCart
  ├── Shipping
  └── Warehouse
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tome cuidado para não dividir os &lt;em&gt;Bounded Contexts&lt;/em&gt; pelos dados e reuso, infelizmente nos como desenvolvedores temos esse hábito. É um erro pensar em &lt;em&gt;Bounded Context&lt;/em&gt; desta forma, isso levará a inconsistências no modelo e ao longo prazo pode acabar comprometendo a evolução do sistema. &lt;em&gt;Bounded Context&lt;/em&gt; é meio difícil de entender no começo, estude bem antes de implementar!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Bounded Context geralmente é recomendado como a primeira linha de divisão em aplicações microservices.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Context Maps
&lt;/h3&gt;

&lt;p&gt;Dado o cenário onde você já identificou e separou os contextos da sua aplicação, agora é hora de entender como eles se comunicam. &lt;em&gt;Context Maps&lt;/em&gt; nos ajudam a entender melhor a barreira entre os &lt;em&gt;Bounded Context&lt;/em&gt; e visualizar como eles interagem entre si. Há alguns patterns para a comunicação entre os contextos de maneira eficiente, porém irie comentar apenas dos dois principais:&lt;/p&gt;

&lt;h4&gt;
  
  
  SharedKernel
&lt;/h4&gt;

&lt;p&gt;Haverá cenários em que teremos, dentro de um &lt;em&gt;Subdomain&lt;/em&gt;, modelos e regras que se aplicam em mais de um &lt;em&gt;Bounded Context&lt;/em&gt;, a fim de evitar duplicidade e não criamos acoplamento podemos ter uma camada que contém o que é comum entre os &lt;em&gt;Bounded Contexts&lt;/em&gt; envolvidos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9g20nv6lzmq5v25h2axw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9g20nv6lzmq5v25h2axw.png" alt="SharedKernel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Podemos exemplificar criando uma camada &lt;strong&gt;Core&lt;/strong&gt; em &lt;strong&gt;Sales&lt;/strong&gt;, ela pode ter o modelo base de &lt;em&gt;Product&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;App/Sales
├── Core
├── Orders
├── Pricing
└── ShoppingCart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Anticorruption Layer
&lt;/h4&gt;

&lt;p&gt;Quando estamos criando um &lt;em&gt;Bounded Context&lt;/em&gt; seguindo a &lt;em&gt;Ubiquios Language&lt;/em&gt; não queremos contaminá-lo com models externas, ou ainda pior, criar acoplamento com partes legadas do sistema. Neste cenário podemos criar uma camada intermediária entre o &lt;em&gt;Bounded Context&lt;/em&gt; e suas dependências. Através de uma interface definida nele, podemos implementar nesta nova camada e traduzir o retorno de chamadas de outros &lt;em&gt;Bounded Contexts&lt;/em&gt; para o nosso. Desta forma conseguimos utilizar recursos externos de forma transparente e sem acoplamento.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F42fcjnnuaxe6cpv67ovg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F42fcjnnuaxe6cpv67ovg.png" alt="AntiCorruption-Layer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Em &lt;strong&gt;Billing&lt;/strong&gt; temos uma camada chamada &lt;em&gt;Integration&lt;/em&gt; que será responsável por obter dados de &lt;em&gt;Customer&lt;/em&gt;, que está dentro do Bounded Context &lt;strong&gt;User&lt;/strong&gt;. Ela também será responsável pela comunicação com a API de pagamentos externa.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;App/Billing
├── src
│ ├── Domain
│ └── Integration
└── tests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Highlights
&lt;/h1&gt;

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

&lt;p&gt;É fundamental para o entendimento do domínio que desenvolvedores e pessoas de negócio trabalhem juntas. Somente com a colaboração e entrevistas constantes podemos extrair os conceitos mais complexos e entender fluxos de negócio de maneira esmiuçada.&lt;/p&gt;

&lt;h2&gt;
  
  
  Foque no Core-Business
&lt;/h2&gt;

&lt;p&gt;Nem toda parte da nossa aplicação tem a mesma relevância. DDD nos permite enxergar com mais clareza o problema que estamos resolvendo e entendendo melhor o que gera valor, devemos então direcionar nossos esforços para os processos que realmente impactam o negócio, aumentando assim a chance de sucesso do nosso software.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evolução constante
&lt;/h2&gt;

&lt;p&gt;Não importa o quão experiente você seja, não há como mapear e ter um design perfeito de início. O processo para destilar o domínio e criar modelos que o representam é iterativo. Além do que conceitos podem e vão mudar, novas necessidades irão surgir e precisamos ficar atentos para alinhar nosso design com o negócio. Podemos ter um sistema 1:1 no começo, porém se não darmos continuidade nas práticas e processos do DDD em alguns meses estaremos defasados. DDD necessita de manutenção constante!&lt;/p&gt;

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

&lt;p&gt;Neste artigo tentei ilustrar com exemplos didáticos o que seria a abordagem do DDD em um software que pretende resolver um domínio complexo. Tenha em mente que devido a sua natureza, nenhum artigo, livro ou curso irá te passar a experiência real do DDD, pois isso envolve trabalhar com pessoas de negócio, distilar e refinar o domínio, colaboração, entre outros. Aprender sobre DDD não é como aprender uma linguagem ou framework novo, envolve muita soft-skill e recursos do dia-a-dia. Os problemas de negócio aqui apresentados são pensados para ilustrar possíveis situações que podem acontecer, porém, somente em um domínio real você irá notar as nuances do DDD e o absorver com mais clareza. Recomendo continuar estudando e, caso tenha a oportunidade, começar a pratica-lo com outros desenvolvedores mais experientes.&lt;/p&gt;

&lt;p&gt;Irei falar mais sobre DDD nos próximos artigos onde abordarei os &lt;strong&gt;Tactical Patterns&lt;/strong&gt; e &lt;strong&gt;Architecture Patterns&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Referências
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com.br/dp/B00XLYUA0W/ref=dp-kindle-redirect?_encoding=UTF8&amp;amp;btkr=1" rel="noopener noreferrer"&gt;Patterns, Principles, and Practices of Domain-Driven Design&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com.br/dp/B00794TAUG/ref=dp-kindle-redirect?_encoding=UTF8&amp;amp;btkr=1" rel="noopener noreferrer"&gt;Domain-Driven Design: Tackling Complexity in the Heart of Software&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thedomaindrivendesign.io/" rel="noopener noreferrer"&gt;The Domain Driven Design&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=TOtA40H2MUs" rel="noopener noreferrer"&gt;DDD (Domain Driven Design) aplicado ao e-commerce - Nelson Senna&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vaadin.com/learn/tutorials/ddd/strategic_domain_driven_design" rel="noopener noreferrer"&gt;Strategic Domain-Driven Design&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ddd</category>
      <category>strategicpatterns</category>
    </item>
    <item>
      <title>Desacoplando chamadas com Mediator</title>
      <dc:creator>Guilherme Camargo</dc:creator>
      <pubDate>Tue, 11 Feb 2020 01:15:20 +0000</pubDate>
      <link>https://dev.to/guisfits/desacoplando-chamadas-com-mediator-38in</link>
      <guid>https://dev.to/guisfits/desacoplando-chamadas-com-mediator-38in</guid>
      <description>&lt;p&gt;Quando precisamos fazer chamadas em pontos da aplicação e não temos uma boa definição para isso, podemos acabar criando dependências que não façam sentido e deixar nosso código acoplado. Neste artigo iremos ver como trabalhar com o pattern Mediator e Command a fim de minimizar este problema e ter um design mais limpo. &lt;/p&gt;

&lt;p&gt;Se você estiver pensando algo do tipo: "Ei, mas eu já consigo desacoplar meu código com interfaces". Sim, é comum (e recomendável) utilizar IoC através de interfaces a fim de ter mais flexibilidade.&lt;br&gt;
Mas te pergunto: Suas interfaces mudam? Com que frequência?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fybg5az14zhmlgqzyofmh.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fybg5az14zhmlgqzyofmh.gif" alt="all the time"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Intefaces são muito importantes em linguagens fortemente tipadas, mas não devemos usá-las como a única solução para todos nossos problemas. Elas não foram feitas para serem alteradas com frequência, seu objetivo é definir um contrato para que qualquer classe que queira implementá-la tenha a mesma assinatura, nos permitindo assim substituir seu comportamento de maneira fácil onde ela é requisitada. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Qualquer alteração em uma interface levará a um refactor considerável em N partes do código.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Porém em certos pontos da nossa aplicação devemos ter mais flexibilidade. Tome como exemplo a camada mais externa de um sistema, seu objetivo é expor os dados para o client. Inevitavelmente vamos ter que mudar parâmetros, adicionar novos campos e fazer alterações baseadas em novas necessidades. Interfaces acabam sendo um inconveniente neste cenário. &lt;/p&gt;

&lt;p&gt;O pattern Mediator pode ser uma boa alternativa neste caso. Ele foi catalogado no conhecido livro "Design Patterns: Elements of Reusable Object-Oriented Software, GOF". Ele é, literalmente, um mediador entre duas classes que não se conhecem, nos permitindo realizar chamadas entre dois pontos sem criar acoplamento. Essas chamadas podem ser feitas através de um Command - outro pattern que teve a mesma origem. O Command trata de encapsular uma chamada através de uma classe que será enviada para execução.&lt;/p&gt;

&lt;p&gt;Um pacote bem conhecido que implementa este pattern é o &lt;a href="https://github.com/jbogard/MediatR" rel="noopener noreferrer"&gt;MediatR&lt;/a&gt;. Iremos utilizá-lo neste exemplo.&lt;/p&gt;
&lt;h2&gt;
  
  
  SHOW ME THE CODE!
&lt;/h2&gt;

&lt;p&gt;Nosso projeto irá conter quatro csprojs, um web chamado API e três classlib chamados Application, Domain e Persistence. Todo o código exemplificado aqui está no meu GitHub.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/guisfits" rel="noopener noreferrer"&gt;
        guisfits
      &lt;/a&gt; / &lt;a href="https://github.com/guisfits/decoupling-calls-with-mediatr" rel="noopener noreferrer"&gt;
        decoupling-calls-with-mediatr
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      How to make calls in a simple way and make your code more organized.
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Tendo o &lt;a href="https://dotnet.microsoft.com/download" rel="noopener noreferrer"&gt;dotnet cli&lt;/a&gt; instalado em sua máquina, vamos adicionar o MediatR ao nosso projeto e logo em seguida o pacote para configurá-lo.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dotnet add API package MediatR&lt;/code&gt;&lt;br&gt;
&lt;code&gt;dotnet add API package MediatR.Extensions.Microsoft.DependencyInjection&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Vamos habilitar o MediatR através da classe startup na nossa API. Iremos primeiro carregar o assemply onde os handlers estaram implementados e passa-lo para o método &lt;em&gt;AddMediatR&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Repare que boa parte do código original foi omitido a fim de simplificar este exemplo. Também irei omitir processos não relacionados a este artigo, para mais detalhes consulte o repositório.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;MediatR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;API&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Startup&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ConfigureServices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IServiceCollection&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;applicationAssembly&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AppDomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CurrentDomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Application"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddMediatR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;applicationAssembly&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Na camada &lt;em&gt;Application&lt;/em&gt; também temos que adicionar o pacote &lt;em&gt;MediatR&lt;/em&gt; a fim de utilizarmos as interfaces &lt;em&gt;IRequest&lt;/em&gt; e &lt;em&gt;IRequestHandler&lt;/em&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Um esclarecimento. O MediatR chama de Request o ato de disparar uma classe para processamento. Não o confunda com HttpRequest. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;dotnet add Application package MediatR&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A interface IRequest tem como objetivo marcar nosso &lt;em&gt;Command&lt;/em&gt; para ser processado por um &lt;em&gt;Handler&lt;/em&gt;. Também podemos utilizar o overload com generics de &lt;em&gt;IRequest&amp;lt;&amp;gt;&lt;/em&gt;, onde passamos T como tipo de retorno que o Handler nos dará deste Command. &lt;/p&gt;

&lt;p&gt;Dentro de &lt;em&gt;Application&lt;/em&gt; iremos criar um comando para adicionar um novo usuário.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;MediatR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Application.Commands&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateUserCommand&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IRequest&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na camada &lt;em&gt;Domain&lt;/em&gt; iremos adicionar nossa entidade &lt;em&gt;User&lt;/em&gt; e seu repository, &lt;em&gt;IUsers&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IUsers&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="n"&gt;newUser&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feito isso iremos para a parte mais importante, o Handler!&lt;br&gt;
Vamos voltar para &lt;em&gt;Application&lt;/em&gt; e criar uma classe chamada &lt;em&gt;UserCommandHandler&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserCommandHandler&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IRequestHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CreateUserCommand&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IUsers&lt;/span&gt; &lt;span class="n"&gt;_users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;UserCommandHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IUsers&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_users&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CreateUserCommand&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CreateUserCommand&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&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;
  
  
  Vamos testar
&lt;/h2&gt;

&lt;p&gt;Em &lt;em&gt;API&lt;/em&gt; vamos criar &lt;em&gt;UserController&lt;/em&gt;, obter a interface &lt;em&gt;IMediator&lt;/em&gt; e enviar o command para execução.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api/users"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IMediator&lt;/span&gt; &lt;span class="n"&gt;_mediator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;UserController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IMediator&lt;/span&gt; &lt;span class="n"&gt;mediator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_mediator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mediator&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpPost&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CreateUserCommand&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_mediator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Created&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Agora vamos fazer uma requisição para a rota criada&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvuw7hrw3gp0smu0ol8ck.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvuw7hrw3gp0smu0ol8ck.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como podemos ver no print, nosso request chegou até o handler.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjp9fqsaz3mxc90tvri4y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjp9fqsaz3mxc90tvri4y.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora confirmamos o retorno com sucesso.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fi8b4oauto5hdva9qv144.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fi8b4oauto5hdva9qv144.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Pontos de Atenção
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Repare que nosso &lt;em&gt;Handler&lt;/em&gt; é uma classe privada, não dando a chance de classes externas o chamarem;&lt;/li&gt;
&lt;li&gt;Como o Handler é uma classe comum do C#, podemos receber as dependências através de IoC;&lt;/li&gt;
&lt;li&gt;Seguindo o &lt;em&gt;Single Responsibility Principle&lt;/em&gt;, seria uma boa prática ter somente um Command por Handler. Assim segmentamos melhor nossas dependências e podemos evoluir a aplicação de maneira isolada;&lt;/li&gt;
&lt;li&gt;Não precisamos dizer explicitamente qual Handler implementa qual Command. O MediatR é esperto o suficiente pra fazer isso automaticamente pra gente;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Recomendações
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://martinfowler.com/bliki/CQRS.html" rel="noopener noreferrer"&gt;CQRS&lt;/a&gt;: MediatR acaba nos ajudando na separação entre Commands e Queries;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://martinfowler.com/articles/201701-event-driven.html" rel="noopener noreferrer"&gt;Event Driven&lt;/a&gt;: MediatR tem outra interface chamada INotification para lançar eventos, pode ser uma boa &lt;strong&gt;alternativa em casos simples&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/jbogard/MediatR/wiki/Behaviors" rel="noopener noreferrer"&gt;IPipelineBehavior&lt;/a&gt;: Farei outro artigo em breve sobre essa funcionalidade;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Vimos neste artigo um simples exemplo de como utilizar o pattern Mediator e Command através do MediatR a fim de um design mais elegante entre as chamadas da nossa aplicação. &lt;/p&gt;

&lt;p&gt;Não se esqueça de procurar a documentação oficial para mais detalhes e fique atento à mudanças em futuras versões.&lt;/p&gt;

&lt;p&gt;Caso tenha gostado não deixe de curtir, comentar e divulgar este post se possível. Também fique a vontade para me seguir por aqui, no GitHub e me adicionar no Linkedin. Este é o meu primeiro artigo técnico, pretendo escrever muitos outros daqui pra frente.&lt;/p&gt;

&lt;p&gt;Espero que esta leitura tenha sido de alguma ajuda pra você.&lt;/p&gt;

&lt;p&gt;Um grande e abraço e até a próxima.&lt;/p&gt;

</description>
      <category>netcore</category>
      <category>designpatterns</category>
      <category>mediator</category>
      <category>command</category>
    </item>
  </channel>
</rss>
