<?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: Hernani Almeida</title>
    <description>The latest articles on DEV Community by Hernani Almeida (@2020nani).</description>
    <link>https://dev.to/2020nani</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F771178%2Fb67b8091-5646-4a25-9b71-23367bc79e7f.png</url>
      <title>DEV Community: Hernani Almeida</title>
      <link>https://dev.to/2020nani</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/2020nani"/>
    <language>en</language>
    <item>
      <title>Angular 21 + Native Federation — Parte 2: Integração, Debug e Boas Práticas</title>
      <dc:creator>Hernani Almeida</dc:creator>
      <pubDate>Tue, 06 Oct 2026 03:02:06 +0000</pubDate>
      <link>https://dev.to/2020nani/angular-21-native-federation-parte-2-integracao-debug-e-boas-praticas-2o65</link>
      <guid>https://dev.to/2020nani/angular-21-native-federation-parte-2-integracao-debug-e-boas-praticas-2o65</guid>
      <description>&lt;p&gt;Na &lt;a href="https://dev.to/2020nani/desacoplando-frontend-com-module-federation-no-angular-21-parte-1-235i"&gt;primeira parte&lt;/a&gt;, vimos como criar uma arquitetura de Micro Frontends utilizando Angular 21 e Native Federation.&lt;/p&gt;

&lt;p&gt;Nesta segunda parte, vamos aprofundar a integração entre &lt;strong&gt;Host&lt;/strong&gt; e &lt;strong&gt;Remote&lt;/strong&gt;, entendendo o que acontece por trás da configuração e, principalmente, alguns pontos que podem gerar erros durante a implementação.&lt;/p&gt;

&lt;p&gt;A ideia é sair de uma configuração que simplesmente "funciona" para entender &lt;strong&gt;por que ela funciona&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Arquitetura que vamos construir
&lt;/h2&gt;

&lt;p&gt;Teremos dois projetos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;angular-micro-frontends/
│
├── mfe-host-2/
│   └── Angular 21
│       └── Host
│
└── mfe-remote-2/
    └── Angular 21
        └── Remote
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Durante o desenvolvimento:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Host
http://localhost:4200

Remote
http://localhost:4201
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O fluxo será:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 HOST
              localhost:4200
                   │
                   │
                   ▼
       federation.manifest.json
                   │
                   │
                   ▼
              Remote :4201
                   │
                   ▼
           remoteEntry.json
                   │
                   ▼
             ./Component
                   │
                   ▼
                 App
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O ponto importante é entender que o Host &lt;strong&gt;não importa diretamente&lt;/strong&gt; o arquivo &lt;code&gt;app.ts&lt;/code&gt; do Remote.&lt;/p&gt;

&lt;p&gt;Ele conhece apenas o nome do Remote e o módulo que o Remote decidiu expor.&lt;/p&gt;




&lt;h1&gt;
  
  
  2. O papel do federation.config.js
&lt;/h1&gt;

&lt;p&gt;No Remote temos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;withNativeFederation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;shareAll&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular-architects/native-federation/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withNativeFederation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mfe-remote-2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;exposes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Component&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;./src/app/app.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="na"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;shareAll&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;singleton&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;strictVersion&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;requiredVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&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="na"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rxjs/ajax&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;rxjs/fetch&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;rxjs/testing&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;rxjs/webSocket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;

  &lt;span class="na"&gt;features&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;ignoreUnusedDeps&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui temos uma das partes mais importantes da configuraçã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="nx"&gt;exposes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Component&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;./src/app/app.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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso significa:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Quando outro aplicativo solicitar &lt;code&gt;./Component&lt;/code&gt;, entregue o módulo localizado em &lt;code&gt;./src/app/app.ts&lt;/code&gt;."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O nome &lt;code&gt;./Component&lt;/code&gt; é um &lt;strong&gt;nome de exposição&lt;/strong&gt;, não precisa ser igual ao nome do arquivo.&lt;/p&gt;

&lt;p&gt;Por exemplo, também poderíamos ter:&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="nx"&gt;exposes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Products&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;./src/app/pages/products/products.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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E no Host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;loadRemoteModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mfe-remote-2&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;./Products&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;h1&gt;
  
  
  3. &lt;code&gt;./Component&lt;/code&gt; não é o nome da classe
&lt;/h1&gt;

&lt;p&gt;Esse é um ponto que pode gerar bastante confusão.&lt;/p&gt;

&lt;p&gt;Temos:&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="nx"&gt;exposes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Component&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;./src/app/app.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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;e dentro do arquivo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;App&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;No Host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;loadRemoteModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mfe-remote-2&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;./Component&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;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;São três coisas diferentes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mfe-remote-2
     │
     └── nome do Remote

./Component
     │
     └── nome da exposição

App
     │
     └── exportação JavaScript/TypeScript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos visualizar assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Host
 │
 │ mfe-remote-2
 │
 ▼
Remote
 │
 │ ./Component
 │
 ▼
src/app/app.ts
 │
 │ export class App
 │
 ▼
m.App
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Portanto, se seu componente se chama:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;App&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;o correto é:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;e não:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  4. O papel do federation.manifest.json
&lt;/h1&gt;

&lt;p&gt;No Host criamos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public/
└── assets/
    └── federation.manifest.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mfe-remote-2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:4201/remoteEntry.json"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse arquivo funciona como um catálogo dos Remotes que o Host conhece.&lt;/p&gt;

&lt;p&gt;Podemos ter vários:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mfe-1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:4201/remoteEntry.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mfe-2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:4202/remoteEntry.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mfe-3"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:4203/remoteEntry.json"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso facilita bastante a configuração de uma arquitetura com vários Micro Frontends.&lt;/p&gt;




&lt;h1&gt;
  
  
  5. Cuidado com o caminho do manifest
&lt;/h1&gt;

&lt;p&gt;No &lt;code&gt;main.ts&lt;/code&gt; do Host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;initFederation&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;@angular-architects/native-federation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;initFederation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/assets/federation.manifest.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./bootstrap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prefira:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/assets/federation.manifest.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;em vez de:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;../assets/federation.manifest.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O motivo é simples: o primeiro é resolvido a partir da raiz da aplicação.&lt;/p&gt;

&lt;p&gt;Se o Host estiver rodando em:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:4200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;o navegador buscará:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:4200/assets/federation.manifest.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos validar isso diretamente no navegador.&lt;/p&gt;

&lt;p&gt;Se retornar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mfe-remote-2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:4201/remoteEntry.json"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;o manifest está sendo servido corretamente.&lt;/p&gt;




&lt;h1&gt;
  
  
  6. &lt;code&gt;remoteEntry.json&lt;/code&gt; é diferente do antigo &lt;code&gt;remoteEntry.js&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;Quem está acostumado com Webpack Module Federation pode estranhar isso.&lt;/p&gt;

&lt;p&gt;No modelo tradicional era comum encontrar:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;No Native Federation trabalhamos com:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;remoteEntry.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:4201/remoteEntry.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse arquivo contém as informações necessárias para que o runtime do Native Federation descubra os módulos expostos pelo Remote.&lt;/p&gt;

&lt;p&gt;Por isso, uma boa estratégia de debug é sempre testar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:4201/remoteEntry.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se ele não abrir, não adianta investigar a rota do Host ainda.&lt;/p&gt;

&lt;p&gt;Primeiro precisamos resolver o Remote.&lt;/p&gt;




&lt;h1&gt;
  
  
  7. A rota do Host
&lt;/h1&gt;

&lt;p&gt;No Angular 21 podemos utilizar componentes standalone diretamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;loadRemoteModule&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;@angular-architects/native-federation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Routes&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;@angular/router&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mfe-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;loadComponent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nf"&gt;loadRemoteModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mfe-remote-2&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;./Component&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;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&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="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;Quando o usuário acessa:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:4200/mfe-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;o Angular executa:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/mfe-1
   │
   ▼
loadComponent()
   │
   ▼
loadRemoteModule()
   │
   ▼
mfe-remote-2
   │
   ▼
./Component
   │
   ▼
App
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  8. &lt;code&gt;path&lt;/code&gt; precisa bater com o link
&lt;/h1&gt;

&lt;p&gt;Um erro simples, mas fácil de passar despercebido.&lt;/p&gt;

&lt;p&gt;Se temos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mfe-2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;loadComponent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;loadRemoteModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mfe-remote-2&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;./Component&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;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;o link precisa ser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;routerLink=&lt;/span&gt;&lt;span class="s"&gt;"/mfe-2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Acesse MFE-2
&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Não:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;routerLink=&lt;/span&gt;&lt;span class="s"&gt;"/mfe-1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Acesse MFE-2
&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parece óbvio, mas em uma aplicação com vários MFEs esse tipo de erro pode fazer parecer que o Federation não está funcionando.&lt;/p&gt;




&lt;h1&gt;
  
  
  9. Não esquecer o RouterOutlet
&lt;/h1&gt;

&lt;p&gt;O Host precisa ter onde renderizar o componente remoto.&lt;/p&gt;

&lt;p&gt;No &lt;code&gt;app.html&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Angular 21 - Micro Frontends&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;nav&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;routerLink=&lt;/span&gt;&lt;span class="s"&gt;"/mfe-1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      Acesse MFE-1
    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;br&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;routerLink=&lt;/span&gt;&lt;span class="s"&gt;"/mfe-2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      Acesse MFE-2
    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;router-outlet&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E como estamos usando standalone components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Component&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;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RouterLink&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RouterOutlet&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;@angular/router&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;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;RouterLink&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;RouterOutlet&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.css&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;App&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;Não basta configurar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;provideRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Também precisamos que o template possua:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;router-outlet&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  10. Não esquecer o &lt;code&gt;provideRouter&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;No &lt;code&gt;app.config.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;ApplicationConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;provideBrowserGlobalErrorListeners&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;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;provideRouter&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;@angular/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;routes&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;./app.routes&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;appConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApplicationConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;provideBrowserGlobalErrorListeners&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nf"&gt;provideRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;routes&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;A cadeia completa fica:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;main.ts
   │
   ▼
bootstrap
   │
   ▼
app.config.ts
   │
   ▼
provideRouter(routes)
   │
   ▼
app.routes.ts
   │
   ▼
loadRemoteModule()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se qualquer uma dessas partes estiver faltando, a rota pode não funcionar.&lt;/p&gt;




&lt;h1&gt;
  
  
  11. O Remote também pode funcionar sozinho
&lt;/h1&gt;

&lt;p&gt;Uma das características mais interessantes dessa arquitetura é que o Remote não precisa existir somente dentro do Host.&lt;/p&gt;

&lt;p&gt;Podemos acessar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:4201/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;diretamente.&lt;/p&gt;

&lt;p&gt;O mesmo componente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;App&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;pode ser usado como aplicação independente.&lt;/p&gt;

&lt;p&gt;E também:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:4200/mfe-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;como Micro Frontend.&lt;/p&gt;

&lt;p&gt;Visualmente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    App
                     │
             ┌───────┴────────┐
             │                │
             ▼                ▼
       Acesso direto       Federation
       :4201               :4200/mfe-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso é muito útil durante o desenvolvimento porque o time responsável pelo MFE pode trabalhar sem precisar subir toda a aplicação Host.&lt;/p&gt;




&lt;h1&gt;
  
  
  12. SSE: o que significa?
&lt;/h1&gt;

&lt;p&gt;Durante o desenvolvimento podemos encontrar no terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Federation SSE] Client connected.
Active connections: 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso é esperado.&lt;/p&gt;

&lt;p&gt;SSE significa:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server-Sent Events&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O Native Federation utiliza esse mecanismo para comunicação entre o servidor de desenvolvimento e o navegador.&lt;/p&gt;

&lt;p&gt;Uma mensagem como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Federation SSE] Client connected.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;significa que o navegador conseguiu estabelecer a conexão.&lt;/p&gt;

&lt;p&gt;Portanto, essa mensagem isoladamente não representa um erro.&lt;/p&gt;

&lt;p&gt;Se aparecer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Federation SSE] Client connected.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;temos uma indicação positiva de que o canal de desenvolvimento foi estabelecido.&lt;/p&gt;




&lt;h1&gt;
  
  
  13. Como fazer troubleshooting
&lt;/h1&gt;

&lt;p&gt;Quando o MFE não aparece, evite alterar várias configurações ao mesmo tempo.&lt;/p&gt;

&lt;p&gt;Faça os testes em ordem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Passo 1 — Remote
&lt;/h2&gt;

&lt;p&gt;Abra:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:4201/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O Remote deve funcionar sozinho.&lt;/p&gt;




&lt;h2&gt;
  
  
  Passo 2 — remoteEntry
&lt;/h2&gt;

&lt;p&gt;Abra:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:4201/remoteEntry.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deve retornar o metadata do Remote.&lt;/p&gt;




&lt;h2&gt;
  
  
  Passo 3 — Manifest
&lt;/h2&gt;

&lt;p&gt;Abra:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:4200/assets/federation.manifest.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deve retornar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mfe-remote-2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:4201/remoteEntry.json"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Passo 4 — Host
&lt;/h2&gt;

&lt;p&gt;Abra:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:4200/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ou a rota correspondente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:4200/mfe-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Passo 5 — DevTools
&lt;/h2&gt;

&lt;p&gt;Abra:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;e verifique a aba:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Procure por:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;federation.manifest.json
remoteEntry.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se ambos carregarem, o próximo ponto a investigar é a resolução do módulo exposto.&lt;/p&gt;




&lt;h1&gt;
  
  
  14. Um erro importante: &lt;code&gt;404&lt;/code&gt; no manifest
&lt;/h1&gt;

&lt;p&gt;Um erro como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET http://localhost:4200/assets/federation.manifest.json 404
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;significa que o navegador não encontrou o manifest.&lt;/p&gt;

&lt;p&gt;Uma configuração comum no Angular 21 é:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"assets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"glob"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"**/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"public"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse caso, o arquivo precisa estar em:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public/assets/federation.manifest.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;e não necessariamente em:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Portanto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mfe-host-2/
│
├── public/
│   └── assets/
│       └── federation.manifest.json
│
└── src/
    └── app/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  15. CSS em Micro Frontends
&lt;/h1&gt;

&lt;p&gt;Outro ponto importante é o isolamento dos estilos.&lt;/p&gt;

&lt;p&gt;Imagine que o Remote tenha:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
└── app/
    ├── app.ts
    ├── app.html
    └── app.css
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos utilizar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.css&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A recomendação para um MFE é priorizar estilos associados aos próprios componentes.&lt;/p&gt;

&lt;p&gt;Por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;32px&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;Evite, quando possível, que o MFE altere globalmente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="err"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;porque o Remote pode ser executado dentro de outro aplicativo.&lt;/p&gt;




&lt;h1&gt;
  
  
  16. Por que evitar CSS global no MFE?
&lt;/h1&gt;

&lt;p&gt;Imagine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Host
│
├── Header
├── Menu
│
└── MFE
     │
     └── styles.css
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se o MFE possui:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&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;esse estilo pode interferir na aplicação Host.&lt;/p&gt;

&lt;p&gt;Por isso, uma boa regra é:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O Host controla o layout global da aplicação. O MFE controla o visual dos componentes que ele entrega.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Isso permite que o mesmo MFE seja executado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;localhost:4201
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ou:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;localhost:4200/mfe-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;sem depender de um CSS global específico do Host.&lt;/p&gt;




&lt;h1&gt;
  
  
  17. Um Remote pode expor mais de um componente
&lt;/h1&gt;

&lt;p&gt;Não precisamos expor apenas o &lt;code&gt;App&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Podemos ter:&lt;/p&gt;

</description>
      <category>angular</category>
      <category>architecture</category>
      <category>frontend</category>
      <category>mfe</category>
    </item>
    <item>
      <title>Desacoplando Frontend com Module Federation no Angular 21 — Parte 1</title>
      <dc:creator>Hernani Almeida</dc:creator>
      <pubDate>Tue, 06 Oct 2026 03:01:12 +0000</pubDate>
      <link>https://dev.to/2020nani/desacoplando-frontend-com-module-federation-no-angular-21-parte-1-235i</link>
      <guid>https://dev.to/2020nani/desacoplando-frontend-com-module-federation-no-angular-21-parte-1-235i</guid>
      <description>&lt;p&gt;Neste artigo vamos atualizar o conceito apresentado no artigo original &lt;strong&gt;"Desacoplando frontend com module-federation Angular - Parte 1"&lt;/strong&gt;, adaptando o projeto para o &lt;strong&gt;Angular 21&lt;/strong&gt; e para a arquitetura moderna de Micro Frontends.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; no Angular moderno, a abordagem recomendada para manter o conceito de Module Federation sem depender do Webpack é utilizar o &lt;strong&gt;Native Federation&lt;/strong&gt;. Ele utiliza ES Modules, Import Maps e integra-se ao Application Builder baseado em esbuild do Angular.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O objetivo continua sendo o mesmo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Criar uma aplicação &lt;strong&gt;Shell/Host&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;Criar aplicações &lt;strong&gt;Remote/Micro Frontends&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;Permitir que o Shell carregue os Micro Frontends em runtime;&lt;/li&gt;
&lt;li&gt;Manter cada aplicação com seu próprio código e deploy;&lt;/li&gt;
&lt;li&gt;Reduzir o acoplamento entre as aplicações.&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  O que são Micro Frontends?
&lt;/h1&gt;

&lt;p&gt;O conceito de Micro Frontends é semelhante ao conceito de Microservices.&lt;/p&gt;

&lt;p&gt;Em vez de termos uma única aplicação frontend grande, podemos dividir a aplicação em partes menores, cada uma responsável por uma determinada área funcional.&lt;/p&gt;

&lt;p&gt;Por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    ┌─────────────────────┐
                    │      SHELL          │
                    │     Angular 21      │
                    └──────────┬──────────┘
                               │
              ┌────────────────┼────────────────┐
              │                │                │
              ▼                ▼                ▼
        ┌───────────┐    ┌───────────┐    ┌───────────┐
        │   MFE 1   │    │   MFE 2   │    │   MFE 3   │
        │  Crédito  │    │   Conta   │    │   Growth  │
        └───────────┘    └───────────┘    └───────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cada Micro Frontend pode possuir:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;seu próprio código;&lt;/li&gt;
&lt;li&gt;seu próprio pipeline;&lt;/li&gt;
&lt;li&gt;seu próprio deploy;&lt;/li&gt;
&lt;li&gt;sua própria equipe;&lt;/li&gt;
&lt;li&gt;seu próprio ciclo de desenvolvimento.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para o usuário final, entretanto, tudo pode aparecer como uma única aplicação.&lt;/p&gt;




&lt;h1&gt;
  
  
  O que mudou desde o Angular utilizado no artigo original?
&lt;/h1&gt;

&lt;p&gt;No artigo original utilizamos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Angular
   +
Webpack
   +
Module Federation
   +
AppModule
   +
AppRoutingModule
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No Angular 21, temos uma arquitetura mais moderna:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Angular 21
   +
Standalone Components
   +
Application Builder / esbuild
   +
Native Federation
   +
ES Modules
   +
Import Maps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;strong&gt;Native Federation&lt;/strong&gt; mantém a mesma ideia conceitual do Module Federation, mas não depende do Webpack. A implementação utiliza padrões nativos do navegador, como ES Modules e Import Maps.&lt;/p&gt;




&lt;h1&gt;
  
  
  Ferramentas necessárias
&lt;/h1&gt;

&lt;p&gt;Para acompanhar este exemplo, recomendo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;li&gt;Angular CLI&lt;/li&gt;
&lt;li&gt;VS Code&lt;/li&gt;
&lt;li&gt;npm&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Verifique as versões:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;-v&lt;/span&gt;

npm &lt;span class="nt"&gt;-v&lt;/span&gt;

ng version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste exemplo vamos utilizar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Angular 21
Angular CLI 21
TypeScript compatível com Angular 21
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  1. Criando o workspace
&lt;/h1&gt;

&lt;p&gt;Vamos criar uma pasta para nosso exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;artigo-mfe

&lt;span class="nb"&gt;cd &lt;/span&gt;artigo-mfe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora vamos criar nossa aplicação Shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng new mfe-host
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Durante a criação, podemos utilizar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Routing: Yes
Stylesheet: CSS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Entre no projeto:&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;cd &lt;/span&gt;mfe-host
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Abra o projeto no VS Code:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;






&lt;h1&gt;
  
  
  2. Criando os Micro Frontends
&lt;/h1&gt;

&lt;p&gt;Vamos voltar para a pasta principal:&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;cd&lt;/span&gt; ..
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora criaremos dois Micro Frontends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng new mfe-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;e:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng new mfe-2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ao final teremos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;artigo-mfe/
│
├── mfe-host/
│
├── mfe-1/
│
└── mfe-2/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nosso objetivo será:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mfe-host
   │
   ├── /mfe-1 → mfe-1
   │
   └── /mfe-2 → mfe-2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  3. Configurando o MFE-1
&lt;/h1&gt;

&lt;p&gt;Entre no projeto:&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;cd &lt;/span&gt;mfe-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora vamos adicionar o Native Federation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng add @angular-architects/native-federation &lt;span class="nt"&gt;--project&lt;/span&gt; mfe-1 &lt;span class="nt"&gt;--port&lt;/span&gt; 4201 &lt;span class="nt"&gt;--type&lt;/span&gt; remote
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;code&gt;ng add&lt;/code&gt; configura automaticamente a aplicação para atuar como um &lt;strong&gt;Remote&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O pacote fornece integração com o Angular CLI e com o Application Builder baseado em esbuild.&lt;/p&gt;




&lt;h1&gt;
  
  
  4. Configurando o MFE-2
&lt;/h1&gt;

&lt;p&gt;Volte para a raiz:&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;cd&lt;/span&gt; ..
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Entre no segundo Micro Frontend:&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;cd &lt;/span&gt;mfe-2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng add @angular-architects/native-federation &lt;span class="nt"&gt;--project&lt;/span&gt; mfe-2 &lt;span class="nt"&gt;--port&lt;/span&gt; 4202 &lt;span class="nt"&gt;--type&lt;/span&gt; remote
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora temos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mfe-1 → http://localhost:4201

mfe-2 → http://localhost:4202
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  5. Configurando o Shell
&lt;/h1&gt;

&lt;p&gt;Volte para a raiz:&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;cd&lt;/span&gt; ..
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Entre no Shell:&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;cd &lt;/span&gt;mfe-host
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora configuraremos o projeto como um &lt;strong&gt;Dynamic Host&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng add @angular-architects/native-federation &lt;span class="nt"&gt;--project&lt;/span&gt; mfe-host &lt;span class="nt"&gt;--port&lt;/span&gt; 4200 &lt;span class="nt"&gt;--type&lt;/span&gt; dynamic-host
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;code&gt;dynamic-host&lt;/code&gt; é importante porque permite que os Micro Frontends sejam definidos através de um manifesto.&lt;/p&gt;

&lt;p&gt;Essa abordagem também permite alterar os endpoints dos Micro Frontends durante o deploy sem precisar recompilar o Shell.&lt;/p&gt;




&lt;h1&gt;
  
  
  6. Estrutura do projeto
&lt;/h1&gt;

&lt;p&gt;Depois da configuração teremos aproximadamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mfe-host/
│
├── src/
│   ├── app/
│   ├── assets/
│   │   └── federation.manifest.json
│   │
│   ├── main.ts
│   └── bootstrap.ts
│
├── federation.config.js
└── package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A configuração de federation ficará separada da configuração normal do Angular.&lt;/p&gt;




&lt;h1&gt;
  
  
  7. Configurando o MFE-1
&lt;/h1&gt;

&lt;p&gt;No projeto &lt;code&gt;mfe-1&lt;/code&gt;, teremos um arquivo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;federation.config.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Uma configuração semelhante a:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;withNativeFederation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;shareAll&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular-architects/native-federation/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withNativeFederation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;

  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mfe-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;exposes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Component&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;./src/app/app.component.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="na"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;shareAll&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;singleton&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;strictVersion&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;requiredVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&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="na"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rxjs/ajax&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;rxjs/fetch&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;rxjs/testing&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;rxjs/webSocket&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;p&gt;O ponto mais importante aqui é:&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="nx"&gt;exposes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Component&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;./src/app/app.component.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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Estamos dizendo:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Quando outro aplicativo solicitar &lt;code&gt;./Component&lt;/code&gt;, entregue o &lt;code&gt;AppComponent&lt;/code&gt; deste Micro Frontend.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O host não precisa conhecer o caminho físico do arquivo.&lt;/p&gt;

&lt;p&gt;Ele conhece apenas:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Essa é uma das ideias fundamentais da Federation.&lt;/p&gt;




&lt;h1&gt;
  
  
  8. Configurando o MFE-2
&lt;/h1&gt;

&lt;p&gt;No projeto &lt;code&gt;mfe-2&lt;/code&gt;, faça a mesma configuraçã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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;withNativeFederation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;shareAll&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular-architects/native-federation/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withNativeFederation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;

  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mfe-2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;exposes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Component&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;./src/app/app.component.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="na"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;shareAll&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;singleton&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;strictVersion&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;requiredVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&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="na"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rxjs/ajax&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;rxjs/fetch&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;rxjs/testing&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;rxjs/webSocket&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;p&gt;Agora temos dois Remotes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mfe-1
  └── ./Component

mfe-2
  └── ./Component
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  9. Configurando o Manifest
&lt;/h1&gt;

&lt;p&gt;Agora vamos para o projeto:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Procure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/assets/federation.manifest.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mfe-1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:4201/remoteEntry.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mfe-2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:4202/remoteEntry.json"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O Manifest funciona como um mapa:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mfe-1 → http://localhost:4201/remoteEntry.json

mfe-2 → http://localhost:4202/remoteEntry.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Uma diferença importante em relação ao artigo original é que agora não trabalhamos diretamente com:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;como acontecia no Module Federation baseado em Webpack.&lt;/p&gt;

&lt;p&gt;O Native Federation utiliza metadados e módulos ES, sendo o &lt;code&gt;remoteEntry.json&lt;/code&gt; utilizado pelo mecanismo para descobrir os recursos publicados pelo Remote.&lt;/p&gt;




&lt;h1&gt;
  
  
  10. Como o Manifest funciona?
&lt;/h1&gt;

&lt;p&gt;O fluxo é aproximadamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                  Browser
                     │
                     ▼
                federation
                 manifest
                     │
          ┌──────────┴──────────┐
          │                     │
          ▼                     ▼
       mfe-1                 mfe-2
          │                     │
          ▼                     ▼
 remoteEntry.json        remoteEntry.json
          │                     │
          ▼                     ▼
    Component              Component
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O Shell não precisa conhecer previamente todo o código dos Micro Frontends.&lt;/p&gt;

&lt;p&gt;Ele conhece apenas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nome do remote
        +
endereço do remote
        +
nome do recurso exposto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  11. Inicialização do Federation
&lt;/h1&gt;

&lt;p&gt;O &lt;code&gt;ng add&lt;/code&gt; também configura o processo de inicialização.&lt;/p&gt;

&lt;p&gt;O &lt;code&gt;main.ts&lt;/code&gt; terá uma estrutura semelhante a:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;initFederation&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;@angular-architects/native-federation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;initFederation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/assets/federation.manifest.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./bootstrap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O processo é:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;main.ts
   │
   ▼
initFederation()
   │
   ▼
federation.manifest.json
   │
   ├── mfe-1
   │
   └── mfe-2
   │
   ▼
bootstrap.ts
   │
   ▼
Angular Application
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A inicialização do Federation acontece antes do bootstrap da aplicação Angular.&lt;/p&gt;




&lt;h1&gt;
  
  
  12. Configurando as rotas do Shell
&lt;/h1&gt;

&lt;p&gt;Agora vamos configurar o carregamento dos Micro Frontends.&lt;/p&gt;

&lt;p&gt;No Angular 21 podemos utilizar Standalone APIs.&lt;/p&gt;

&lt;p&gt;Crie ou altere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/app/app.routes.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Utilize:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Routes&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;@angular/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loadRemoteModule&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;@angular-architects/native-federation&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;

  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mfe-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;loadComponent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nf"&gt;loadRemoteModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mfe-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Component&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;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&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="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mfe-2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;loadComponent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nf"&gt;loadRemoteModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mfe-2&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;./Component&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;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&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;Observe a diferença em relação ao artigo original.&lt;/p&gt;

&lt;p&gt;Antes tínhamos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;loadChildren&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;e:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;AppModule&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora podemos trabalhar diretamente com:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;loadComponent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;e:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;AppComponent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso acontece porque o Angular moderno utiliza Standalone Components como abordagem principal.&lt;/p&gt;

&lt;p&gt;O Native Federation suporta esse modelo diretamente.&lt;/p&gt;




&lt;h1&gt;
  
  
  13. Configurando o AppComponent do Shell
&lt;/h1&gt;

&lt;p&gt;No:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mfe-host/src/app/app.component.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;podemos utilizar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Angular 21 - Micro Frontends&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;nav&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;routerLink=&lt;/span&gt;&lt;span class="s"&gt;"/mfe-1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      Acesse MFE-1
    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;br&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;routerLink=&lt;/span&gt;&lt;span class="s"&gt;"/mfe-2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      Acesse MFE-2
    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;router-outlet&amp;gt;&amp;lt;/router-outlet&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora teremos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Angular 21 - Micro Frontends

Acesse MFE-1

Acesse MFE-2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  14. Configurando o MFE-1
&lt;/h1&gt;

&lt;p&gt;Vamos alterar o componente do &lt;code&gt;mfe-1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Component&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;@angular/core&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;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&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;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;div&amp;gt;
      &amp;lt;h2&amp;gt;MFE-1&amp;lt;/h2&amp;gt;

      &amp;lt;p&amp;gt;
        Este conteúdo foi carregado remotamente.
      &amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppComponent&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;h1&gt;
  
  
  15. Configurando o MFE-2
&lt;/h1&gt;

&lt;p&gt;No &lt;code&gt;mfe-2&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Component&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;@angular/core&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;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&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;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;div&amp;gt;
      &amp;lt;h2&amp;gt;MFE-2&amp;lt;/h2&amp;gt;

      &amp;lt;p&amp;gt;
        Este conteúdo também foi carregado remotamente.
      &amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppComponent&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;h1&gt;
  
  
  16. Subindo os projetos
&lt;/h1&gt;

&lt;p&gt;Agora precisamos executar os três projetos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terminal 1 — MFE-1
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;mfe-1

ng serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aplicação:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:4201
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Terminal 2 — MFE-2
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;mfe-2

ng serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aplicação:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:4202
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Terminal 3 — Shell
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;mfe-host

ng serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aplicação:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:4200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  17. Testando
&lt;/h1&gt;

&lt;p&gt;Abra:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:4200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clique:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Acesse MFE-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O Shell irá executar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;loadRemoteModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mfe-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Component&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;p&gt;O Native Federation irá localizar:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;no:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;federation.manifest.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;e descobrir:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:4201/remoteEntry.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois carregará:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;que aponta para:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mfe-1/src/app/app.component.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O resultado será:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────┐
│          MFE-HOST                │
│                                  │
│  Acesse MFE-1                    │
│  Acesse MFE-2                    │
│                                  │
│  ┌────────────────────────────┐  │
│  │           MFE-1            │  │
│  │                            │  │
│  │ Conteúdo carregado         │  │
│  │ remotamente                │  │
│  └────────────────────────────┘  │
│                                  │
└──────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  18. O que está acontecendo por baixo?
&lt;/h1&gt;

&lt;p&gt;Quando acessamos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:4200/mfe-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;o Angular Shell não possui necessariamente o código do &lt;code&gt;mfe-1&lt;/code&gt; no bundle inicial.&lt;/p&gt;

&lt;p&gt;O fluxo é:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser
   │
   ▼
Angular Shell
   │
   ▼
Router
   │
   ▼
loadRemoteModule()
   │
   ▼
federation.manifest.json
   │
   ▼
mfe-1
   │
   ▼
remoteEntry.json
   │
   ▼
./Component
   │
   ▼
AppComponent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso permite que o Micro Frontend seja desenvolvido e publicado separadamente.&lt;/p&gt;




&lt;h1&gt;
  
  
  19. Compartilhamento de dependências
&lt;/h1&gt;

&lt;p&gt;Outro ponto importante da Federation é o compartilhamento de dependências.&lt;/p&gt;

&lt;p&gt;Nossa configuração possui:&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="nx"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;shareAll&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;singleton&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;strictVersion&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;requiredVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&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;p&gt;Isso permite compartilhar bibliotecas entre o Shell e os Micro Frontends.&lt;/p&gt;

&lt;p&gt;Por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Shell
 └── Angular

MFE-1
 └── Angular

MFE-2
 └── Angular
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em vez de necessariamente carregar múltiplas cópias das mesmas dependências, o Federation pode compartilhar essas bibliotecas.&lt;/p&gt;

&lt;p&gt;O &lt;code&gt;singleton: true&lt;/code&gt; é especialmente importante para bibliotecas que devem possuir uma única instância no runtime, como as principais bibliotecas do Angular.&lt;/p&gt;




&lt;h1&gt;
  
  
  20. Por que utilizar Native Federation no Angular 21?
&lt;/h1&gt;

&lt;p&gt;No artigo original utilizamos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Webpack Module Federation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa abordagem continua sendo importante e o ecossistema de Module Federation continua evoluindo.&lt;/p&gt;

&lt;p&gt;Porém, para um projeto novo utilizando Angular 21, o Native Federation é uma opção muito interessante porque:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;integra-se ao Application Builder do Angular;&lt;/li&gt;
&lt;li&gt;utiliza esbuild;&lt;/li&gt;
&lt;li&gt;trabalha com ES Modules;&lt;/li&gt;
&lt;li&gt;utiliza Import Maps;&lt;/li&gt;
&lt;li&gt;não depende diretamente do Webpack;&lt;/li&gt;
&lt;li&gt;mantém o modelo mental do Module Federation;&lt;/li&gt;
&lt;li&gt;suporta Standalone Components;&lt;/li&gt;
&lt;li&gt;suporta SSR;&lt;/li&gt;
&lt;li&gt;possui versões alinhadas às versões do Angular.&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  21. Estrutura final
&lt;/h1&gt;

&lt;p&gt;Ao final desta primeira parte teremos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;artigo-mfe/
│
├── mfe-host/
│   │
│   ├── src/
│   │   ├── app/
│   │   │   ├── app.component.ts
│   │   │   └── app.routes.ts
│   │   │
│   │   ├── assets/
│   │   │   └── federation.manifest.json
│   │   │
│   │   ├── main.ts
│   │   └── bootstrap.ts
│   │
│   ├── federation.config.js
│   └── package.json
│
├── mfe-1/
│   │
│   ├── src/
│   │   └── app/
│   │       └── app.component.ts
│   │
│   ├── federation.config.js
│   └── package.json
│
└── mfe-2/
    │
    ├── src/
    │   └── app/
    │       └── app.component.ts
    │
    ├── federation.config.js
    └── package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;Neste artigo configuramos uma arquitetura de Micro Frontends utilizando &lt;strong&gt;Angular 21 + Native Federation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Criamos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 Angular 21
                     │
                     ▼
              ┌─────────────┐
              │    HOST     │
              │    :4200    │
              └──────┬──────┘
                     │
          ┌──────────┴──────────┐
          │                     │
          ▼                     ▼
   ┌─────────────┐       ┌─────────────┐
   │    MFE-1    │       │    MFE-2    │
   │    :4201    │       │    :4202    │
   └─────────────┘       └─────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O Shell é responsável pela experiência principal da aplicação, enquanto os Micro Frontends podem ser desenvolvidos e publicados de forma independente.&lt;/p&gt;

&lt;p&gt;Na próxima parte podemos avançar para uma arquitetura mais próxima de um cenário real, trabalhando com:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;múltiplas páginas dentro de cada Micro Frontend;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;loadChildren()&lt;/code&gt; com rotas remotas;&lt;/li&gt;
&lt;li&gt;comunicação entre Shell e Micro Frontends;&lt;/li&gt;
&lt;li&gt;compartilhamento de serviços;&lt;/li&gt;
&lt;li&gt;autenticação;&lt;/li&gt;
&lt;li&gt;Angular Material;&lt;/li&gt;
&lt;li&gt;gerenciamento de estado;&lt;/li&gt;
&lt;li&gt;deploy independente;&lt;/li&gt;
&lt;li&gt;ambientes &lt;code&gt;DEV&lt;/code&gt;, &lt;code&gt;HML&lt;/code&gt; e &lt;code&gt;PROD&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;versionamento dos Micro Frontends;&lt;/li&gt;
&lt;li&gt;tratamento de indisponibilidade de um Remote;&lt;/li&gt;
&lt;li&gt;arquitetura recomendada para projetos corporativos.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Troubleshooting — Problemas na instalação do Native Federation
&lt;/h1&gt;

&lt;p&gt;Durante a configuração do &lt;strong&gt;Native Federation&lt;/strong&gt;, o comando apresentado no artigo pode apresentar erro dependendo da versão do Angular instalada no ambiente.&lt;/p&gt;

&lt;p&gt;O comando inicial utilizado no artigo é:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng add @angular-architects/native-federation &lt;span class="nt"&gt;--project&lt;/span&gt; mfe-remote-2 &lt;span class="nt"&gt;--port&lt;/span&gt; 4201 &lt;span class="nt"&gt;--type&lt;/span&gt; remote
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em alguns ambientes, o Angular CLI pode não conseguir encontrar automaticamente uma versão compatível do pacote.&lt;/p&gt;

&lt;p&gt;Um exemplo de erro é:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Could not find a compatible version with `latest`.
Searching for a compatible version.

Cannot read properties of undefined (reading 'latest')

An unhandled exception occurred:
Cannot read properties of undefined (reading 'latest')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse problema está relacionado à resolução automática da versão do pacote e &lt;strong&gt;não necessariamente a um problema no projeto Angular&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Verifique a versão do Angular
&lt;/h2&gt;

&lt;p&gt;Antes de corrigir o problema, execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Angular CLI       : 21.2.25
Angular           : 21.2.25
Node.js           : 24.15.0
Package Manager   : npm 12.2.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A versão do Angular deve ser utilizada para escolher uma versão compatível do Native Federation.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Instale uma versão compatível manualmente
&lt;/h2&gt;

&lt;p&gt;Caso o &lt;code&gt;ng add&lt;/code&gt; apresente o erro descrito acima, em vez de utilizar o &lt;code&gt;latest&lt;/code&gt;, instale explicitamente uma versão compatível.&lt;/p&gt;

&lt;p&gt;Para um projeto utilizando &lt;strong&gt;Angular 21.2.x&lt;/strong&gt;, por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @angular-architects/native-federation@21.2.6 &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois execute o schematic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng generate @angular-architects/native-federation:init &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--project&lt;/span&gt; mfe-remote-2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--port&lt;/span&gt; 4201 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--type&lt;/span&gt; remote
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No Windows/Git Bash, o comando também pode ser executado em uma única linha:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng generate @angular-architects/native-federation:init &lt;span class="nt"&gt;--project&lt;/span&gt; mfe-remote-2 &lt;span class="nt"&gt;--port&lt;/span&gt; 4201 &lt;span class="nt"&gt;--type&lt;/span&gt; remote
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Regra geral
&lt;/h2&gt;

&lt;p&gt;A ideia é utilizar uma versão do Native Federation compatível com a versão principal do Angular do projeto.&lt;/p&gt;

&lt;p&gt;Por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Angular 21.x
     ↓
Native Federation 21.x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Portanto, se estiver utilizando outra versão do Angular, primeiro verifique:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;e então consulte a versão do &lt;code&gt;@angular-architects/native-federation&lt;/code&gt; compatível com essa versão.&lt;/p&gt;

&lt;p&gt;Evite simplesmente instalar a versão &lt;code&gt;latest&lt;/code&gt; quando o Angular CLI não conseguir determinar automaticamente uma versão compatível.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Caso tenha instalado uma versão incorreta
&lt;/h2&gt;

&lt;p&gt;Se uma tentativa anterior instalou uma versão incompatível, remova o pacote:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm uninstall @angular-architects/native-federation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Limpe a instalação:&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;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; node_modules package-lock.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No Windows PowerShell, utilize:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Recurse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;node_modules&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;package-lock.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois reinstale as dependências:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E instale novamente a versão compatível:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @angular-architects/native-federation@21.2.6 &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por fim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng generate @angular-architects/native-federation:init &lt;span class="nt"&gt;--project&lt;/span&gt; mfe-remote-2 &lt;span class="nt"&gt;--port&lt;/span&gt; 4201 &lt;span class="nt"&gt;--type&lt;/span&gt; remote
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Resumo
&lt;/h2&gt;

&lt;p&gt;Se o comando original funcionar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng add @angular-architects/native-federation &lt;span class="nt"&gt;--project&lt;/span&gt; mfe-remote-2 &lt;span class="nt"&gt;--port&lt;/span&gt; 4201 &lt;span class="nt"&gt;--type&lt;/span&gt; remote
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;continue normalmente com o tutorial.&lt;/p&gt;

&lt;p&gt;Caso apareça:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Could not find a compatible version with `latest`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;faça:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;identifique a versão do Angular e instale manualmente uma versão compatível do Native Federation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @angular-architects/native-federation@&amp;lt;versao-compativel&amp;gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;e execute o schematic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng generate @angular-architects/native-federation:init &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--project&lt;/span&gt; mfe-remote-2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--port&lt;/span&gt; 4201 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--type&lt;/span&gt; remote
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Importante:&lt;/strong&gt; as versões dos pacotes podem mudar ao longo do tempo. Portanto, sempre verifique a compatibilidade entre a versão do Angular instalada no projeto e a versão do Native Federation utilizada.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://dev.to/2020nani/angular-21-native-federation-parte-2-integracao-debug-e-boas-praticas-2o65"&gt;Link parte 2&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Referências&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Artigo original: &lt;em&gt;Desacoplando frontend com module-federation Angular - Parte 1&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Angular Architects — &lt;em&gt;Micro Frontends with Modern Angular&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Angular Architects — &lt;em&gt;Native Federation&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Documentação do &lt;code&gt;@angular-architects/native-federation&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

</description>
      <category>angular</category>
      <category>architecture</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Implementando Singleton, Factory e Observer com novas features versoes recentes Java</title>
      <dc:creator>Hernani Almeida</dc:creator>
      <pubDate>Sun, 13 Apr 2025 21:41:51 +0000</pubDate>
      <link>https://dev.to/2020nani/implementando-singleton-factory-e-observer-com-novas-features-versoes-recentes-java-48jd</link>
      <guid>https://dev.to/2020nani/implementando-singleton-factory-e-observer-com-novas-features-versoes-recentes-java-48jd</guid>
      <description>&lt;p&gt;Neste post vamos aprender 3 dos design patterns essenciais para o desenvolvimento de software utilizando a linguagem ´Java´ e novas features adicionadas na versão 21 e 24 do java.&lt;br&gt;
Este projeto simula um sistema de cadastro de usuários, utilizando os padrões de design &lt;strong&gt;Singleton&lt;/strong&gt;, &lt;strong&gt;Factory&lt;/strong&gt; e &lt;strong&gt;Observer&lt;/strong&gt;. Cada padrão foi escolhido para resolver problemas específicos dentro da arquitetura.&lt;br&gt;
Primeiro criamos a classe &lt;code&gt;UsuarioController&lt;/code&gt; que tera a responsabilidade de expor nossa api para ser acessada via rest através do meto http POST.&lt;br&gt;
UsuarioController&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.designpatterns.application.controller;

import com.designpatterns.application.mapper.input.UsuarioRequest;
import com.designpatterns.application.mapper.output.UsuarioResponse;
import com.designpatterns.core.usuario.UsuarioService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UsuarioController {
    private final UsuarioService usuarioService;

    public UsuarioController(UsuarioService usuarioService) {
        this.usuarioService = usuarioService;
    }

    @PostMapping("usuario")
    public UsuarioResponse cadastraUsuario(@RequestBody UsuarioRequest request) {
        return usuarioService.createUser(request.converteUsuario()).converteResponse();
    }
}

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

&lt;/div&gt;



&lt;p&gt;A classe UsuarioController depende de um objeto do tipo &lt;code&gt;UsuarioService&lt;/code&gt; para realizar suas operações. Em vez de criar diretamente uma instância de UsuarioService (o que resultaria em alto acoplamento), definimos essa dependência como um parâmetro no construtor utilizando a injeção de dependência do spring, quando o Spring Container detecta essa classe, ele identifica o construtor e injeta automaticamente uma instância de UsuarioService, que já foi configurada no contexto da aplicação (geralmente definida como um Bean no Spring).&lt;br&gt;
&lt;strong&gt;Observação:&lt;/strong&gt; Nesse momento já estamos utilizando o design pattern &lt;code&gt;Singleton&lt;/code&gt; pois o Spring fornece essa instância única em toda a aplicação, que já foi criada e gerenciada pelo Container Spring, caso fosse necessário que tivesses uma classe nova todas as vezes que instanciada em um constructor e necessário utilizarmos a annotation &lt;code&gt;@Scope("prototype")&lt;/code&gt; para referenciar esse contexto ao Spring conforme a imagem abaixo.&lt;/p&gt;

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

&lt;p&gt;Logo mais veremos outra forma de utilizar o design pattern Singleton.&lt;br&gt;
UsuarioService&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.designpatterns.core.usuario;

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

@Service
public class UsuarioService {
    private final ApplicationEventPublisher eventPublisher;

    public UsuarioService(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }


    public Usuario createUser(Usuario usuario) {
        System.out.println("Usuário cadastrado com sucesso: " + usuario.nome());
        eventPublisher.publishEvent(new UsuarioCadastradoEvent(this, usuario));
        return usuario;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dentro da nossa classe de serviço UsuarioService encontramos outro design pattern que podemos utilizar, o &lt;strong&gt;&lt;em&gt;Observer&lt;/em&gt;&lt;/strong&gt;.&lt;br&gt;
O Observer é utilizado para desacoplar o envio de notificações do fluxo de cadastro de usuário. Quando um usuário é cadastrado, múltiplos observadores podem reagir a esse evento de maneira independente.&lt;br&gt;
Temos injetado em nossa classe de serviço a classe &lt;code&gt;ApplicationEventPublisher&lt;/code&gt; que é uma interface do Spring Framework responsável por publicar eventos dentro do contexto da aplicação, nos permitindo que o UsuarioService publique eventos de forma desacoplada. Ou seja, o service não precisa conhecer diretamente os objetos que vão reagir ao evento.&lt;br&gt;
&lt;strong&gt;OBS:&lt;/strong&gt; A implementação do padrão Observer utilizando o &lt;code&gt;ApplicationEventPublisher&lt;/code&gt;e uma abordagem moderna e desacoplada provida pelo Spring. Com isso, sempre que um novo usuário é cadastrado, um evento do tipo &lt;code&gt;UsuarioCadastradoEvent&lt;/code&gt; é publicado.&lt;/p&gt;

&lt;p&gt;Esse evento sera tratado pela classe &lt;code&gt;UsuarioEventListener&lt;/code&gt;, que atua como "observador", reagindo ao evento publicado para enviar notificações com base na preferência do usuário (SMS ou E-mail).&lt;/p&gt;

&lt;p&gt;Essa abordagem traz os benefícios do padrão Observer (desacoplamento e reatividade), utilizando os recursos do próprio Spring.&lt;/p&gt;

&lt;p&gt;Nesse caso, ela dispara o evento &lt;code&gt;UsuarioCadastradoEvent&lt;/code&gt; com o usuário recém-criado. O Spring então notifica automaticamente qualquer classe anotada com @EventListener e que esteja ouvindo esse tipo de evento.&lt;br&gt;
Vamos criar entao a classe UsuarioCadastradoEvent e também o listener responsável por ouvir esse evento e implementar o envio de notificação de email/sms.&lt;br&gt;
UsuarioCadastradoEvent&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.designpatterns.core.usuario;

import org.springframework.context.ApplicationEvent;

public class UsuarioCadastradoEvent extends ApplicationEvent {

    private final Usuario usuario;
    public UsuarioCadastradoEvent(Object source, Usuario usuario) {
        super(source);
        this.usuario = usuario;
    }

    public Usuario getUsuario() { return usuario; }
}

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

&lt;/div&gt;



&lt;p&gt;UsuarioEventListener&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.designpatterns.core.usuario;

import com.designpatterns.core.notification.EmailNotification;
import com.designpatterns.core.notification.NotificationFactory;
import com.designpatterns.core.notification.SmsNotification;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
public class UsuarioEventListener {
    private final NotificationFactory factory;

    public UsuarioEventListener(NotificationFactory factory) {
        this.factory = factory;
    }

    @EventListener
    public void handle(UsuarioCadastradoEvent event) {
        Usuario usuario = event.getUsuario();
        factory.getNotificationsFor(usuario.preferencia())
               .forEach(n -&amp;gt; {
                   if (n instanceof EmailNotification email) {
                       email.notificate(usuario, "E-mail: Bem-vindo, " + usuario.nome() + "!");
                   } else if (n instanceof SmsNotification sms) {
                       sms.notificate(usuario, "SMS: Bem-vindo, " + usuario.nome() + "!");
                   }
               });
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Observação:&lt;/strong&gt; Note que utilizamos o &lt;code&gt;instanceof com pattern matching&lt;/code&gt;, o uso de pattern matching com instanceof facilita muito o código ao evitar castings explícitos. Isso torna o código mais legível, seguro e moderno, nos permitindo acessar diretamente a instância com cast implícito e mais legibilidade sendo muito útil quando queremos tratar notificações de forma personalizada por tipo uma das melhorias de linguagem do Java 24&lt;/p&gt;

&lt;p&gt;Queremos em nosso sistema notificar o usuário via &lt;code&gt;email&lt;/code&gt; e &lt;code&gt;sms&lt;/code&gt; que o cadastro foi efetuado com sucesso.&lt;br&gt;
Vamos utilizar um novo design pattern dentro da classe que esta ouvindo o email através da classe &lt;code&gt;NotificationFactory&lt;/code&gt;&lt;br&gt;
No projeto, a classe NotificationFactory contem instâncias de diferentes tipos de notificadores, como EmailNotification e SmsNotification, sem que o código cliente precise conhecer os detalhes específicos de cada implementação. Isso é alcançado através do design pattern Factory, que promove a criação de objetos de forma encapsulada e flexível.&lt;/p&gt;

&lt;p&gt;🧱 Factory Pattern com switch expression e Injeção de Dependência&lt;br&gt;
Aqui, vamos implementar uma Factory que retorna uma lista de notificações com base na preferência do usuário, como Email, SMS, ou ambos. Vamos usar o padrão Factory para encapsular a lógica de criação dessas instâncias.&lt;br&gt;
NotificationFactory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.designpatterns.core.notification;

import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class NotificationFactory {

    private final EmailNotification email;
    private final SmsNotification sms;

    public NotificationFactory(EmailNotification email, SmsNotification sms) {
        this.email = email;
        this.sms = sms;
    }
    public List&amp;lt;Notification&amp;gt; getNotificationsFor(String preferencia) {
        return switch (preferencia.toLowerCase()) {
            case "email" -&amp;gt; List.of(email);
            case "sms" -&amp;gt; List.of(sms);
            case "ambos" -&amp;gt; List.of(email, sms);
            default -&amp;gt; List.of();
        };
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🏭 O que essa Factory faz?&lt;br&gt;
A NotificationFactory decide, com base na preferência do usuário (se ele deseja receber notificações por email, SMS ou ambos), qual(is) instância(s) de notificação retornar. A implementação do switch expression torna o código mais limpo, sem a necessidade de múltiplos if ou else.&lt;/p&gt;

&lt;p&gt;💡 O que foi aplicado de moderno aqui?&lt;br&gt;
Injeção de Dependência com Spring (@Component): As instâncias de EmailNotification e SmsNotification são injetadas automaticamente pelo Spring, facilitando o gerenciamento das dependências.&lt;/p&gt;

&lt;p&gt;switch expression (Java 14+): Melhorias no Java que tornam a seleção de valores mais legível e com menos código boilerplate, comparado ao switch tradicional.&lt;/p&gt;

&lt;p&gt;✅ Exemplo de uso da Factory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NotificationFactory factory = new NotificationFactory(email, sms);
List&amp;lt;Notification&amp;gt; notifications = factory.getNotificationsFor("ambos");

notifications.forEach(notification -&amp;gt; notification.send());
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔄 O que mais podemos fazer?&lt;br&gt;
Flexibilidade: Caso surjam novos tipos de notificação, como Push ou WhatsApp, podemos facilmente estender a Factory para lidar com esses novos tipos.&lt;/p&gt;

&lt;p&gt;Extensibilidade: Adicionar novas opções ao método getNotificationsFor se torna trivial, mantendo o código limpo e expansível.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observação:&lt;/strong&gt; Criaremos a interface &lt;code&gt;Notification&lt;/code&gt; e as classes &lt;code&gt;EmailNotification&lt;/code&gt; e 'SmsNotification' que implementam essa interface.&lt;/p&gt;

&lt;p&gt;No projeto, usamos a seguinte construção moderna das versões recentes do java para criar a interface Notification&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdl39yf0bagvg6ftipwe4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdl39yf0bagvg6ftipwe4.png" alt="Image description" width="800" height="132"&gt;&lt;/a&gt;&lt;br&gt;
Essa linha define uma interface selada &lt;strong&gt;(sealed interface)&lt;/strong&gt;, que traz uma poderosa funcionalidade: restringir quais classes podem implementar ou estender a interface.&lt;/p&gt;

&lt;p&gt;Notification&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.designpatterns.core.notification;

import com.designpatterns.core.usuario.Usuario;

public sealed interface Notification permits EmailNotification, SmsNotification {
    void notificate(Usuario usuario, String mensagem);
}


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

&lt;/div&gt;



&lt;p&gt;Agora vamos criar as classes &lt;code&gt;EmailNotification&lt;/code&gt; e &lt;code&gt;SmsNotification&lt;/code&gt; que implementam a interface Notification e através do método notificate enviam a mensagem ao usuário.&lt;br&gt;
EmailNotification&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.designpatterns.core.notification;

import com.designpatterns.core.usuario.Usuario;
import org.springframework.stereotype.Component;

@Component
public final class EmailNotification implements Notification {
    public void notificate(Usuario usuario, String mensagem) {
        System.out.printf("Enviando EMAIL para %s (%s): %s%n",
                usuario.nome(), usuario.email(), mensagem);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SmsNotification&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.designpatterns.core.notification;

import com.designpatterns.core.usuario.Usuario;
import org.springframework.stereotype.Component;

@Component
public final class SmsNotification implements Notification {
    public void notificate(Usuario usuario, String mensagem) {
        System.out.printf("Enviando SMS para %s (%s): %s%n",
                usuario.nome(), usuario.telefone(), mensagem);
    }
}


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

&lt;/div&gt;



&lt;p&gt;Podemos agora testar nossa aplicação e validar o envio das notificações de email e sms quando um usuário e cadastrado.&lt;/p&gt;

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

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

&lt;p&gt;Este projeto demonstra como combinar design patterns clássicos com os novos recursos das versoes mais recentes do Java, usando um sistema simples de cadastro de usuários com notificações via e-mail e SMS.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔧 Padrões Utilizados
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🔒 Singleton
&lt;/h3&gt;

&lt;p&gt;O padrão Singleton foi aplicado com o uso do Spring Boot para garantir que o serviço &lt;code&gt;UsuarioService&lt;/code&gt; tenham apenas uma instância durante todo o ciclo de vida da aplicação.&lt;/p&gt;

&lt;h3&gt;
  
  
  🏭 Factory
&lt;/h3&gt;

&lt;p&gt;Utilizamos uma &lt;code&gt;NotificationFactory&lt;/code&gt; para encapsular a criação das instâncias de notificações (&lt;code&gt;EmailNotification&lt;/code&gt; e &lt;code&gt;SmsNotification&lt;/code&gt;) com base em um tipo definido na escolha do usuario.&lt;/p&gt;

&lt;h3&gt;
  
  
  👀 Observer
&lt;/h3&gt;

&lt;p&gt;O padrão Observer permite que diferentes canais de notificação sejam observadores do evento de cadastro de usuário. Assim, sempre que um novo usuário é registrado, todos os canais registrados recebem a notificação.&lt;/p&gt;

&lt;h2&gt;
  
  
  🆕 Features das versoes recentes do Java
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sealed interface&lt;/code&gt;: restringe quais classes podem implementar uma interface, trazendo mais segurança e controle ao design.&lt;/li&gt;
&lt;li&gt;Pattern matching com &lt;code&gt;instanceof&lt;/code&gt;: permite validações de tipo mais limpas e seguras.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;switch&lt;/code&gt; com enum: possibilita o tratamento completo dos tipos permitidos com checagem de exaustividade pelo compilador.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  📦 Classes Principais
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Usuario&lt;/code&gt;: representa o modelo de dados do usuário, contendo informações como nome e preferência de notificação (e-mail ou SMS).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Notification&lt;/code&gt;: interface selada (&lt;code&gt;sealed interface&lt;/code&gt;) que define o contrato para os tipos de notificação. Ela é implementada por:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;EmailNotification&lt;/code&gt;: responsável por enviar notificações por e-mail.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SmsNotification&lt;/code&gt;: responsável por enviar notificações via SMS.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;NotificationFactory&lt;/code&gt;: aplica o padrão &lt;strong&gt;Factory&lt;/strong&gt;, sendo responsável por fornecer a instância correta de &lt;code&gt;Notification&lt;/code&gt; com base na preferência informada pelo usuário (por exemplo, "email" ou "sms").&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;NotificationService&lt;/code&gt;: atua como &lt;strong&gt;publisher&lt;/strong&gt; de eventos no padrão Observer moderno via &lt;code&gt;ApplicationEventPublisher&lt;/code&gt;, enviando eventos de forma desacoplada para serem tratados por listeners.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;UsuarioService&lt;/code&gt;: encapsula a lógica de cadastro de usuários e é responsável por acionar a notificação através da publicação de um evento (&lt;code&gt;UsuarioCadastradoEvent&lt;/code&gt;) que será capturado posteriormente pelo listener.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;UsuarioEventListener&lt;/code&gt;: classe que observa os eventos de usuários cadastrados. Utiliza pattern matching com &lt;code&gt;switch&lt;/code&gt; para tratar dinamicamente o tipo de notificação a ser enviada, de forma segura e moderna.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;UsuarioCadastradoEvent&lt;/code&gt;: classe que representa o evento de domínio publicado após o cadastro de um novo usuário. Contém os dados do usuário para consumo pelos observers.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

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

&lt;p&gt;A combinação dos padrões de projeto com os novos recursos das recentes versões do Java  trouxe maior robustez, legibilidade e extensibilidade ao projeto. Essa abordagem é ideal para arquiteturas modernas e escaláveis.&lt;/p&gt;




&lt;p&gt;O projeto está disponível no GitHub. Sua estrela é muito bem-vinda se você achou o conteúdo relevante:&lt;br&gt;
🔗 &lt;a href="https://github.com/2020nani/designpatternj" rel="noopener noreferrer"&gt;DesignPatterns&lt;/a&gt;&lt;br&gt;
Desenvolvido para fins educacionais por Hernani Almeida&lt;/p&gt;

</description>
      <category>java</category>
      <category>designpatterns</category>
      <category>springboot</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Solucionar erro imagem module-federation</title>
      <dc:creator>Hernani Almeida</dc:creator>
      <pubDate>Tue, 10 Dec 2024 00:07:29 +0000</pubDate>
      <link>https://dev.to/2020nani/solucionar-erro-imagem-module-federation-c3k</link>
      <guid>https://dev.to/2020nani/solucionar-erro-imagem-module-federation-c3k</guid>
      <description>&lt;p&gt;Este artigo visa corrigir o erro que temos quando utilizamos &lt;strong&gt;module-federation&lt;/strong&gt; para configurar aplicações micro-frontends com &lt;strong&gt;angular&lt;/strong&gt;&lt;br&gt;
Resumindo o erro ocorre pois quando rodamos as aplicações e o angular vai buscar o path da imagem, automaticamente, ele assume o path do host como base e, caso a imagem não esteja alocada no host, não encontra o caminho da imagem.&lt;br&gt;
Isso pode interferir nas vantagens de uso do microfrontend que seriam:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Independência Total: Cada equipe poder trabalhar em um microfrontend de forma autônoma, pois no caso de imagens teriam que estar adicionando a imagem na aplicação host.&lt;/li&gt;
&lt;li&gt;Deploy Independente: Cada microfrontend poder ser deployado de forma independente, pois sempre haverá a dependência de deploy da app host em caso de mudar ou adicionar imagens.
Veja este exemplo, tenho na aplicação &lt;strong&gt;MFE&lt;/strong&gt; a imagem e o path da imagem passado de maneira correta.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz0wdrlv4r4rnle1nyseh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz0wdrlv4r4rnle1nyseh.png" alt="Image description" width="800" height="468"&gt;&lt;/a&gt;&lt;br&gt;
 Porem quando acesso a aplicação rodando recebo um erro 404 ao buscar o caminho da imagem&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0rob7hxv9h4qkt7ona53.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0rob7hxv9h4qkt7ona53.png" alt="Image description" width="800" height="265"&gt;&lt;/a&gt;&lt;br&gt;
Note na imagem que a aplicação utilizou o base path da aplicação host para buscar a imagem &lt;strong&gt;&lt;a href="http://localhost:4200/" rel="noopener noreferrer"&gt;http://localhost:4200/&lt;/a&gt;&lt;/strong&gt;, onde não temos a imagem alocada, por isso recebemos o erro.&lt;/p&gt;

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

&lt;p&gt;Bora lá resolver isso então, vamos criar um pipe &lt;em&gt;UrlFormatterPipe&lt;/em&gt; na aplicação &lt;strong&gt;mfe&lt;/strong&gt; para forçarmos o angular utilizar o path correto ao buscar a imagem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'urlFormatter'
})
export class UrlFormatterPipe implements PipeTransform {

  transform(value: string): string {
    return __webpack_public_path__ + value;
  }

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

&lt;/div&gt;



&lt;p&gt;Resumindo o que estamos fazendo no pipe e buscar o path publico da aplicação mfe através da variável global &lt;strong&gt;&lt;strong&gt;webpack_public_path&lt;/strong&gt;&lt;/strong&gt; (ou seja mesmo em ambiente produtivo ira nos retornar o base path da aplicação mfe rodando) e concatenamos com o path da imagem que recebemos dentro do parametro &lt;strong&gt;value&lt;/strong&gt;.&lt;br&gt;
Vamos utilizar o pipe no path da imagem agora e ver o resultado.&lt;/p&gt;

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

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

&lt;p&gt;Voalá imagem apareceu com sucesso e podemos confirmar no devTools que o base path esta vindo da aplicação &lt;strong&gt;mfe&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;E isso ai devs mas um conhecimento passado, deixarei aqui link do artigo que mostro como configurar um micro frontend angular utilizando module federation, &lt;a href="https://dev.to/2020nani/desacoplando-frontend-com-module-federation-angular-parte-1-5enm"&gt;aplicação utilizada para explicar a correção do path da imagem&lt;/a&gt;, e link do repositório no meu &lt;a href="https://github.com/2020nani/mfe-article" rel="noopener noreferrer"&gt;github&lt;/a&gt; para quem quiser acessar o projeto&lt;br&gt;
Deixo aqui também meu &lt;a href="https://www.linkedin.com/in/nanialmeida/" rel="noopener noreferrer"&gt;linkedin&lt;/a&gt; e &lt;a href="https://www.instagram.com/her_almeida40/" rel="noopener noreferrer"&gt;instagram&lt;/a&gt; para quem quiser me adicionar, grato a todos que leram este artigo e bora aprender galera.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>modulefederation</category>
      <category>microfrontend</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Api Rest .Net completa com JwtToken integração com api ViaCep utilizando padrão de arquitetura clean architecture - parte 3</title>
      <dc:creator>Hernani Almeida</dc:creator>
      <pubDate>Thu, 01 Aug 2024 02:57:04 +0000</pubDate>
      <link>https://dev.to/2020nani/api-rest-net-completa-com-jwttoken-integracao-com-api-viacep-utilizando-padrao-de-arquitetura-clean-architecture-parte-3-21o9</link>
      <guid>https://dev.to/2020nani/api-rest-net-completa-com-jwttoken-integracao-com-api-viacep-utilizando-padrao-de-arquitetura-clean-architecture-parte-3-21o9</guid>
      <description>&lt;p&gt;Ferramentas necessárias:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dotnet.microsoft.com/pt-br/download/visual-studio-sdks" rel="noopener noreferrer"&gt;Sdk .net&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/desktop/windows/install/#:~:text=%20Install%20Docker%20Desktop%20on%20Windows%20%F0%9F%94%97%20,to%20authorize%20the%20installer%20and%20proceed...%20More%20" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://visualstudio.microsoft.com/pt-br/vs/community/" rel="noopener noreferrer"&gt;Visual Studio Community&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/2020nani/api-rest-net-completa-com-jwttoken-integracao-com-api-viacep-utilizando-padrao-de-arquitetura-clean-architecture-parte-2-im"&gt;Ter completado a implementação mostrada no artigo anterior&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Seguimos com a construção da nossa api, neste artigo vamos estruturar a parte de segurança de nossa api, bloqueando acesso de quem não esta autenticado ou sem autorização para acessar algum recurso.&lt;br&gt;
Para realizar essa proteção vamos utilizar a autenticação via &lt;strong&gt;JWT&lt;/strong&gt; &lt;code&gt;JSON WEB TOKEN&lt;/code&gt; bora la.&lt;br&gt;
Para iniciar vamos instalar as bibliotecas necessárias, conforme vimos nos artigos anteriores vamos utilizar o gerenciador de pacotes do Nuget&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuffvqgikctcjgvas0koe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuffvqgikctcjgvas0koe.png" alt="Image description" width="800" height="434"&gt;&lt;/a&gt;&lt;br&gt;
Dentro do gerenciador busque e instale essas duas bibliotecas&lt;/p&gt;

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

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

&lt;p&gt;Feito isso, dentro da pasta &lt;code&gt;Controllers&lt;/code&gt; que fica na camada de &lt;code&gt;Infrastructure&lt;/code&gt; de nossa api (vide artigo 1 para entender a definição da arquitetura escolhida) vamos proteger nossas classes de acesso conforme imagem abaixo.&lt;/p&gt;

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

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

&lt;p&gt;&lt;strong&gt;Observação:&lt;/strong&gt; Como passamos a anotação &lt;code&gt;[Authorize(Roles = "ADMIN")]&lt;/code&gt; acima do nome da nossa classe isso faz com que todos os endpoints de acesso sejam protegidos, atraves do JWTToken e a role de permissão concedida ao usuario, caso passemos a anotação acima de um método especifico dentro da nossa classe (conforme imagem abaixo) apenas esse método será protegido o acesso.&lt;/p&gt;

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

&lt;p&gt;Feito isso e necessário mais uma configuração dentro na nossa classe Program.cs, dentro do metodo &lt;code&gt;Main&lt;/code&gt; vamos instanciar uma variável &lt;code&gt;secretKey&lt;/code&gt;, essa assinatura é utilizada para garantir a integridade do token, no caso, se ele foi modificado e se realmente foi gerado por você, você pode gerar um &lt;a href="https://guidgenerator.com/" rel="noopener noreferrer"&gt;Guid&lt;/a&gt; para garantir a integridade dessa chave e que ninguem a conheça para decodificar seu token.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnah369yr3g4gk291wp9q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnah369yr3g4gk291wp9q.png" alt="Image description" width="766" height="116"&gt;&lt;/a&gt;&lt;br&gt;
Logo acima da configuração &lt;code&gt;app.UseAuthorization()&lt;/code&gt; instancia a config &lt;code&gt;app.UseAuthentication()&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;Agora adicionamos a configuração para geração do token conforme imagem abaixo.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;ValidateIssuer = true&lt;/strong&gt;: Configura que na geração do token seja validado se o &lt;em&gt;Issuer&lt;/em&gt; contido no token e igual ao que passamos na config &lt;strong&gt;ValidIssuer&lt;/strong&gt;.&lt;br&gt;
&lt;strong&gt;ValidateAudience= true&lt;/strong&gt;: : Configura que na geração do token seja validado se o &lt;em&gt;Audience&lt;/em&gt; contido no token e igual ao que passamos na config &lt;strong&gt;ValidAudience&lt;/strong&gt;.&lt;br&gt;
&lt;strong&gt;ValidateLifetime = true&lt;/strong&gt;: Configura a validação de expiração do token gerado.&lt;br&gt;
&lt;strong&gt;ValidateIssuerSigningKey&lt;/strong&gt;: Valida se a chave secreta contida na geração do token e a mesma que passamos na variavel &lt;code&gt;secretKey&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Nossa classe &lt;code&gt;Main&lt;/code&gt; ficara conforme abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
using FirstApi.Application.UseCases.CasesEmployer.ConsultEmployer;
using FirstApi.Application.UseCases.CasesEmployer.DeleteEmployer;
using FirstApi.Application.UseCases.CasesEmployer.Register;
using FirstApi.Application.UseCases.CasesEmployer.UpdateEmployer;
using FirstApi.Application.UseCases.CasesUser.ConsultUser;
using FirstApi.Application.UseCases.CasesUser.DeleteUser;
using FirstApi.Application.UseCases.CasesUser.RegisterUser;
using FirstApi.Application.UseCases.CasesUser.UpdateUser;
using FirstApi.Application.UseCases.PasswordHasher;
using FirstApi.Domain.Repositories;
using FirstApi.Infrastructure.Data;
using FirstApi.Infrastructure.Handler;
using FirstApi.Infrastructure.Integration.ViaCep;
using FirstApi.Infrastructure.Integration.ViaCep.Refit;
using FirstApi.Infrastructure.Repositories;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Refit;
using System.Text;

namespace FirstApi
{
    public class Program
    {

        public static void Main(string[] args)
        {
            string secretKey = "e0606215-c2e4-46fe-8d73-a77e1fa4f45a";
            var builder = WebApplication.CreateBuilder(args);
            // Configure logging
            builder.Logging.ClearProviders();
            builder.Logging.AddConsole();
            builder.Logging.AddDebug();
            // Configure data base access
            builder.Services.AddDbContext&amp;lt;SystemDbContext&amp;gt;(
                options =&amp;gt; options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
            // Add repositories to the container.
            builder.Services.AddScoped&amp;lt;IEmployerRepository, EmployerRepository&amp;gt;();
            builder.Services.AddScoped&amp;lt;IUserRepository, UserRepository&amp;gt;();
            // Add services to the container.
            // employer
            builder.Services.AddScoped&amp;lt;IRegisterEmployerService, RegisterEmployerService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IUpdateEmployerService, UpdateEmployerService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IConsultEmployerService, ConsultEmployerService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IDeleteEmployerService, DeleteEmployerService&amp;gt;();
            // user
            builder.Services.AddScoped&amp;lt;IRegisterUserService, RegisterUserService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IUpdateUserService, UpdateUserService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IConsultUserService, ConsultUserService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IDeleteUserService, DeleteUserService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IPasswordHasher, PasswordHasher&amp;gt;();
            // client viacep
            builder.Services.AddScoped&amp;lt;IViaCepIntegrationService, ViaCepIntegrationService&amp;gt;();
            // Add client refit
            builder.Services.AddRefitClient&amp;lt;IViaCepIntegrationRefit&amp;gt;().ConfigureHttpClient(c =&amp;gt;
            {
                c.BaseAddress = new Uri("https://viacep.com.br");
            }
            );

            builder.Services.AddControllers();
            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();

            // Config authentication
            builder.Services.AddAuthentication(options =&amp;gt;
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(options =&amp;gt;
            {
                options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
                {
                    ValidateIssuer = true,
                    ValidateAudience= true,
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = true,
                    ValidIssuer = "emprise",
                    ValidAudience = "firstApi",
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey))
                };
            });

            var app = builder.Build();

            // Configure the HTTP request pipeline.
            if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }

            app.UseHttpsRedirection();
            app.UseAuthentication();
            app.UseAuthorization();

            // global error handler
            app.UseMiddleware&amp;lt;GlobalExceptionHandler&amp;gt;();

            app.MapControllers();

            app.Run();
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pronto nossa api ja esta protegida, se fizermos um request sem passar o token de acesso vamos receber um status code &lt;code&gt;401&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;Vamos agora implementar um endpoint para criar um login e gerar um &lt;code&gt;JsonToken&lt;/code&gt; para acessarmos nossa api, na nossa camada &lt;code&gt;Application&lt;/code&gt; vamos criar um caso de uso &lt;code&gt;PasswordHasher&lt;/code&gt; responsavel por criptografar o password do usuario e armazenar banco de dados e mais um caso de uso chamado Login conforme imagens abaixo.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvqs1i6qb6mgiiys24mpc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvqs1i6qb6mgiiys24mpc.png" alt="Image description" width="336" height="191"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;IPasswordHasher&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;namespace FirstApi.Application.UseCases.PasswordHasher
{
    public interface IPasswordHasher
    {
        public string Hash(string password);

        public bool Verify(string passwordHash, string password);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;PasswordHasher&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using System.Security.Cryptography;

namespace FirstApi.Application.UseCases.PasswordHasher
{
    public class PasswordHasher : IPasswordHasher
    {
        private int SaltSize = 128 / 8;
        private int KeySize = 256 / 8;
        private int Iterations = 10000;
        private static HashAlgorithmName _hash = HashAlgorithmName.SHA256;
        private char Delimiter = ';'; 
        string IPasswordHasher.Hash(string password)
        {
            var salt = RandomNumberGenerator.GetBytes(SaltSize);
            var hash = Rfc2898DeriveBytes.Pbkdf2(password, salt, Iterations,_hash, KeySize);
            return string.Join(Delimiter, Convert.ToBase64String(salt), Convert.ToBase64String(hash));
        }

        bool IPasswordHasher.Verify(string passwordHash, string password)
        {
            var elements = passwordHash.Split(Delimiter);
            var salt = Convert.FromBase64String(elements[0]);
            var hash = Convert.FromBase64String(elements[1]);
            var hashInput = Rfc2898DeriveBytes.Pbkdf2(password, salt, Iterations, _hash, KeySize);
            return CryptographicOperations.FixedTimeEquals(hash, hashInput);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ILoginService&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;namespace FirstApi.Application.UseCases.CasesAuth.Login
{
    public interface ILoginService
    {
        public LoginOutput Execute(LoginInput input);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;LoginService&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using FirstApi.Application.UseCases.PasswordHasher;
using FirstApi.Domain.Entities;
using FirstApi.Domain.Enums;
using FirstApi.Domain.Repositories;
using FirstApi.Infrastructure.CustomException;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;

namespace FirstApi.Application.UseCases.CasesAuth.Login
{
    public class LoginService : ILoginService
    {
        private readonly IUserRepository _userRepository;
        private readonly IPasswordHasher _passwordHasher;

        public LoginService(IUserRepository userRepository, IPasswordHasher passwordHasher)
        {
            _userRepository = userRepository;
            _passwordHasher = passwordHasher;
        }

        LoginOutput ILoginService.Execute(LoginInput input)
        {
            User user = _userRepository.FindUserByEmail(input.Email).Result;
            if (user == null || user.Password == null || user.Email == null)
            {
                throw new AppNotFoundException("Credenciais Invalidas teste");
            }

            if (_passwordHasher.Verify(user.Password, input.Password))
            {
                return new LoginOutput().Convert(user, this.generateJwtToken(user.Roles));
            }

            throw new BadHttpRequestException("Credenciais Invalidas");

        }

        private string generateJwtToken(List&amp;lt;Roles&amp;gt; roles)
        {
            string secretKey = "e0606215-c2e4-46fe-8d73-a77e1fa4f45a";
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
            var claims = new List&amp;lt;Claim&amp;gt;
            {
                new Claim("login","admin"),
                new Claim("name", "System Administrator")
            };

            claims.AddRange(roles.Select(role =&amp;gt; new Claim(ClaimTypes.Role, role.ToString())));

            var token = new JwtSecurityToken(
                issuer: "emprise",
                audience: "firstApi",
                claims: claims,
                expires: DateTime.UtcNow.AddHours(2),
                signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)
                );

            return new JwtSecurityTokenHandler().WriteToken(token);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;LoginInput&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;namespace FirstApi.Application.UseCases.CasesAuth.Login
{
    public class LoginInput
    {
        public required string Email { get; set; }
        public required string Password { get; set; }


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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;LoginOutput&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using FirstApi.Domain.Entities;

namespace FirstApi.Application.UseCases.CasesAuth.Login
{
    public class LoginOutput
    {
        public int Id { get; set; }
        public string? UserName { get; set; }
        public string? AccessToken { get; set; }

        internal LoginOutput Convert(User user, string token)
        {
            Id = user.Id;
            UserName = user.Name;
            AccessToken = token;
            return this;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Obs: Duvida sobre a implementação veja a primeira parte do artigo pois explico a responsabilidade de cada classe construido dentro do caso de uso.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Será necessário também mudarmos nossa entity &lt;code&gt;User.cs&lt;/code&gt; pois precisamos adicionar uma lista de &lt;code&gt;Roles&lt;/code&gt; para cada usuário salvo que será as permissões de acessos que esse usuário possui mesmo tendo um token &lt;code&gt;JwtToken&lt;/code&gt; gerado.&lt;br&gt;
Mude a classe User.cs para que fique assim&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using FirstApi.Domain.Enums;
using FirstApi.Domain.ValueObjects;
using FirstApi.Infrastructure.Integration.ViaCep;

namespace FirstApi.Domain.Entities
{
    public class User
    {
        public int Id { get; set; }
        public string? Name { get; set; }
        public string? Email { get; set; }
        public string? Password { get; set; }
        public List&amp;lt;Roles&amp;gt;? Roles { get; set; }
        public Endereco? Endereco { get; set; }

        public Endereco GetEndereco(ViaCepResponse response)
        {
            Endereco endereco = new Endereco();
            if(response is null)
            {
                return endereco;
            }
            endereco.Complemento = response.Complemento;
            endereco.Cep = response.Cep;
            endereco.Bairro = response.Bairro;
            endereco.Logradouro = response.Logradouro;
            endereco.Localidade = response.Localidade;
            endereco.Cep = response.Cep;
            endereco.Unidade = response.Unidade;
            endereco.Uf = response.Uf;
            return endereco;
        }
    }
}

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

&lt;/div&gt;



&lt;p&gt;Crie o enum contendo as roles de permissões que seu sistema possui conforme exemplo abaixo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fik3yj6n6d3m5qw86ntjk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fik3yj6n6d3m5qw86ntjk.png" alt="Image description" width="800" height="232"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Obs:&lt;/strong&gt; Como estamos mudando nossa entity será necessário mudar o mapeamento dessa tabela na classe UserMap.cs.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;UserMap&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using FirstApi.Domain.Entities;
using FirstApi.Domain.Enums;
using FirstApi.Domain.ValueObjects;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;

namespace FirstApi.Infrastructure.Data.Map
{
    public class UserMap : IEntityTypeConfiguration&amp;lt;User&amp;gt;
    {
        public void Configure(EntityTypeBuilder&amp;lt;User&amp;gt; builder)
        {
           var userRolesConverter = new ValueConverter&amp;lt;List&amp;lt;Roles&amp;gt;, string&amp;gt;(
           v =&amp;gt; string.Join(',', v.Select(e =&amp;gt; e.ToString())),
           v =&amp;gt; v.Split(new[] { ',' }, StringSplitOptions.None)
           .Select(e =&amp;gt; (Roles)Enum.Parse(typeof(Roles), e)).ToList());
            builder.HasKey(x =&amp;gt; x.Id);
            builder.Property(x =&amp;gt; x.Name).IsRequired().HasMaxLength(255);
            builder.Property(x =&amp;gt; x.Email).IsRequired();
            builder.Property(x =&amp;gt; x.Password).IsRequired();
            builder.Property(x =&amp;gt; x.Roles).HasConversion(userRolesConverter).IsRequired();
            builder.ToTable("Users")
                .OwnsOne(x =&amp;gt; x.Endereco, x =&amp;gt;
                {
                    x.Property(a =&amp;gt; a.Unidade)
                    .HasColumnName("unidade")
                    .IsRequired();
                    x.Property(a =&amp;gt; a.Complemento)
                    .HasColumnName("complemento")
                    .IsRequired();
                    x.Property(a =&amp;gt; a.Cep)
                    .HasColumnName("cep")
                    .IsRequired();
                    x.Property(a =&amp;gt; a.Bairro)
                    .HasColumnName("bairro")
                    .IsRequired();
                    x.Property(a =&amp;gt; a.Logradouro)
                    .HasColumnName("logradouro")
                    .IsRequired();
                    x.Property(a =&amp;gt; a.Uf)
                    .HasColumnName("uf")
                    .IsRequired();
                    x.Property(a =&amp;gt; a.Localidade)
                    .HasColumnName("localidade")
                    .IsRequired();
                });
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feito isso, para facilitar, apague todas as tabelas do seu banco de dados e exclua a pasta ´Migrations´ do seu projeto, apos isso rode os seguintes comandos em ordem dentro do console gerenciador de pacotes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1- Add-Migration InitialDB -Context &amp;lt;nome do contexto a ser migrado&amp;gt;
2- Update-Database -Context &amp;lt;nome do contexto a ser migrado&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Como citamos nos artigos anteriores, por ter construído nossa app utilizando o padrão &lt;code&gt;Clean Architecture&lt;/code&gt; e o conceito de &lt;strong&gt;domínio não amenico&lt;/strong&gt;, nos traz uma facilidade de mudar alguma logica em nossa api. Precisamos mudar a logica de salvar o usuário em nosso banco de dados, pois e necessário agora salvar também as Roles de acesso que esse usuário terá para acessar nossa aplicação, para isso vamos fazer apenas mudanças na classe de input e output desse caso de uso, que ficara assim.&lt;br&gt;
&lt;strong&gt;RegisterUserInput&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using FirstApi.Application.CustomValidations;
using FirstApi.Application.UseCases.PasswordHasher;
using FirstApi.Domain.Entities;
using FirstApi.Domain.Enums;
using FirstApi.Infrastructure.Integration.ViaCep;
using System.ComponentModel.DataAnnotations;

namespace FirstApi.Application.UseCases.CasesUser.RegisterUser
{
    public class RegisterUserInput
    {
        public string? Name { get; set; }

        [EmailAddress(ErrorMessage = "Invalid email address.")]
        public required string Email { get; set; }
        [Password(ErrorMessage = "Password must be at least 8 characters long and contain an uppercase letter, a lowercase letter, a number, and a special character.")]
        public string? Password { get; set; }
        public List&amp;lt;Roles&amp;gt;? Roles { get; set; }
        public string? Cep { get; set; }

        public User Convert(IPasswordHasher hasher, ViaCepResponse response)
        {

            User user = new User();
            user.Name = Name;
            user.Password = hasher.Hash(Password);
            user.Email = Email;
            user.Roles = Roles;
            user.Endereco = user.GetEndereco(response);
            return user;
        }
    }
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;RegisterUserOutput&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using FirstApi.Domain.Entities;
using FirstApi.Domain.ValueObjects;

namespace FirstApi.Application.UseCases.CasesUser.RegisterUser
{
    public class RegisterUserOutput
    {
        public int Id { get; set; }
        public string? Name { get; set; }
        public string? Email { get; set; }
        public Endereco? Endereco { get; set; }

        public List&amp;lt;string&amp;gt;? Roles { get; set; }

        public RegisterUserOutput Convert(User user)
        {
            Id = user.Id;
            Name = user.Name;
            Email = user.Email;
            Endereco = user.Endereco;
            Roles = user.Roles.Select(x =&amp;gt; x.ToString()).ToList();
            return this;
        }
    }
}

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

&lt;/div&gt;



&lt;p&gt;Pronto, feito isso vamos implementar agora na camada de acesso externo de nossa aplicação um controller para fazer a autenticação/autorização do usuário.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;AuthController&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using FirstApi.Application.UseCases.CasesAuth.Login;
using Microsoft.AspNetCore.Mvc;

namespace FirstApi.Infrastructure.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class AuthController
    {
        private ILoginService _loginService;

        public AuthController(ILoginService loginService)
        {
            _loginService = loginService;
        }

        [HttpPost]
        public LoginOutput Login(LoginInput login)
        {
            return _loginService.Execute(login);
        }

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

&lt;/div&gt;



&lt;p&gt;Como adicionamos interfaces de services e necessário configurar a inejçao de dependência destes na nossa classe &lt;code&gt;Program.cs&lt;/code&gt; e também adicionar uma configuração para que o swagger entenda o fluxo de autenticação da nossa api. Sua classe &lt;code&gt;Program.cs&lt;/code&gt; devera ficar assim.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
using FirstApi.Application.UseCases.CasesAuth.Login;
using FirstApi.Application.UseCases.CasesEmployer.ConsultEmployer;
using FirstApi.Application.UseCases.CasesEmployer.DeleteEmployer;
using FirstApi.Application.UseCases.CasesEmployer.Register;
using FirstApi.Application.UseCases.CasesEmployer.UpdateEmployer;
using FirstApi.Application.UseCases.CasesUser.ConsultUser;
using FirstApi.Application.UseCases.CasesUser.DeleteUser;
using FirstApi.Application.UseCases.CasesUser.RegisterUser;
using FirstApi.Application.UseCases.CasesUser.UpdateUser;
using FirstApi.Application.UseCases.PasswordHasher;
using FirstApi.Domain.Repositories;
using FirstApi.Infrastructure.Data;
using FirstApi.Infrastructure.Handler;
using FirstApi.Infrastructure.Integration.ViaCep;
using FirstApi.Infrastructure.Integration.ViaCep.Refit;
using FirstApi.Infrastructure.Repositories;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Refit;
using System.Text;

namespace FirstApi
{
    public class Program
    {

        public static void Main(string[] args)
        {
            string secretKey = "e0606215-c2e4-46fe-8d73-a77e1fa4f45a";
            var builder = WebApplication.CreateBuilder(args);
            // Configure logging
            builder.Logging.ClearProviders();
            builder.Logging.AddConsole();
            builder.Logging.AddDebug();
            // Configure data base access
            builder.Services.AddDbContext&amp;lt;SystemDbContext&amp;gt;(
                options =&amp;gt; options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
            // Add repositories to the container.
            builder.Services.AddScoped&amp;lt;IEmployerRepository, EmployerRepository&amp;gt;();
            builder.Services.AddScoped&amp;lt;IUserRepository, UserRepository&amp;gt;();
            // Add services to the container.
            // employer
            builder.Services.AddScoped&amp;lt;IRegisterEmployerService, RegisterEmployerService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IUpdateEmployerService, UpdateEmployerService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IConsultEmployerService, ConsultEmployerService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IDeleteEmployerService, DeleteEmployerService&amp;gt;();
            // user
            builder.Services.AddScoped&amp;lt;IRegisterUserService, RegisterUserService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IUpdateUserService, UpdateUserService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IConsultUserService, ConsultUserService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IDeleteUserService, DeleteUserService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IPasswordHasher, PasswordHasher&amp;gt;();
            builder.Services.AddScoped&amp;lt;ILoginService,LoginService&amp;gt;();
            // client viacep
            builder.Services.AddScoped&amp;lt;IViaCepIntegrationService, ViaCepIntegrationService&amp;gt;();
            // Add client refit
            builder.Services.AddRefitClient&amp;lt;IViaCepIntegrationRefit&amp;gt;().ConfigureHttpClient(c =&amp;gt;
            {
                c.BaseAddress = new Uri("https://viacep.com.br");
            }
            );

            builder.Services.AddControllers();
            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen(sw =&amp;gt;
            {
                sw.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo {
                    Title = "ApiFirst", Version = "v1"
                });
                var securitySchema = new OpenApiSecurityScheme
                {
                    Name = "Jwt Authentication",
                    Description = "Enter with your Jwt Bearer Token",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.Http,
                    Scheme = "Bearer",
                    Reference = new OpenApiReference
                    {
                        Id = JwtBearerDefaults.AuthenticationScheme,
                        Type = ReferenceType.SecurityScheme
                    }
                };
                sw.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, securitySchema);
                sw.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    { securitySchema, new string[] { } }
                });
            });

            // Config authentication
            builder.Services.AddAuthentication(options =&amp;gt;
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(options =&amp;gt;
            {
                options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
                {
                    ValidateIssuer = true,
                    ValidateAudience= true,
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = true,
                    ValidIssuer = "emprise",
                    ValidAudience = "firstApi",
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey))
                };
            });

            var app = builder.Build();

            // Configure the HTTP request pipeline.
            if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }

            app.UseHttpsRedirection();
            app.UseAuthentication();
            app.UseAuthorization();

            // global error handler
            app.UseMiddleware&amp;lt;GlobalExceptionHandler&amp;gt;();

            app.MapControllers();

            app.Run();
        }
    }
}

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

&lt;/div&gt;



&lt;p&gt;Pronto, agora e só rodar a aplicação e testarmos a parte de segurança no swagger.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Teste usuario com token mas sem role de acesso&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;Dados usuarios&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;code&gt;Gerando token usuario id 3, sem role de Admin&lt;/code&gt;&lt;/p&gt;

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

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

&lt;p&gt;&lt;code&gt;Request endpoint lista usuários, necessário role de Admin para acesso&lt;/code&gt;&lt;br&gt;
Retorno statuscode 403, ou seja estamos autenticado porem nao autorizados a acessar o recurso.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frvre6ndxbncj3pvagpag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frvre6ndxbncj3pvagpag.png" alt="Image description" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Teste usuario com token e role de acesso&lt;/strong&gt;&lt;br&gt;
Vamos utilizar o mesmo token gerado com user id = 3, que possui a role USERCOMMON solicitada para buscar os dados de Employers.&lt;/p&gt;

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

&lt;p&gt;&lt;code&gt;Request endpoint lista employers, necessário role de USERCOMMON para acesso&lt;/code&gt;&lt;br&gt;
Retorno statuscode 200, ou seja estamos autenticado e autorizados a acessar o recurso.&lt;/p&gt;

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

&lt;p&gt;Finalizamos por aqui galerinha, deixe seu feedback por favor sobre o artigo e deixo aqui minhas redes sociais para quem quiser me adicionar e trocar uma ideia sobre desenvolvimento de softwares para aprendermos juntos, ate a próxima.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/nanialmeida/" rel="noopener noreferrer"&gt;linkedin&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/2020nani" rel="noopener noreferrer"&gt;github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>dotnet</category>
      <category>architecture</category>
      <category>cleancode</category>
    </item>
    <item>
      <title>Api Rest .Net completa com JwtToken, integração com api ViaCep utilizando padrão de arquitetura clean architecture</title>
      <dc:creator>Hernani Almeida</dc:creator>
      <pubDate>Sat, 27 Jul 2024 01:50:21 +0000</pubDate>
      <link>https://dev.to/2020nani/api-rest-net-completa-com-jwttoken-e-integracao-com-api-viacep-utilizando-padrao-de-arquitetura-clean-architecture-5b1n</link>
      <guid>https://dev.to/2020nani/api-rest-net-completa-com-jwttoken-e-integracao-com-api-viacep-utilizando-padrao-de-arquitetura-clean-architecture-5b1n</guid>
      <description>&lt;p&gt;Ferramentas necessárias:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dotnet.microsoft.com/pt-br/download/visual-studio-sdks" rel="noopener noreferrer"&gt;Sdk .net&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/desktop/windows/install/#:~:text=%20Install%20Docker%20Desktop%20on%20Windows%20%F0%9F%94%97%20,to%20authorize%20the%20installer%20and%20proceed...%20More%20" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://visualstudio.microsoft.com/pt-br/vs/community/" rel="noopener noreferrer"&gt;Visual Studio Community&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Neste artigo vamos implementar uma api rest utilizando o padrao &lt;strong&gt;Clean Architecture&lt;/strong&gt;, nessa api iremos &lt;strong&gt;integrar com uma api externa para buscar dados, configurar e acessar banco de dados postgres fazendo mapeamento e relacionamento de tabelas, criptografar dados para salvar banco de dados e configurar o swagger para realizar a autenticação e o crud em nossa api&lt;/strong&gt;, bora la.&lt;br&gt;
Para iniciar e necessário fazer o download e instalar o Sdk do .net e a ide Visual Studio Community, links logo acima.&lt;br&gt;
Dentro do terminal digite o comando &lt;code&gt;dotnet --version&lt;/code&gt; e devera retornar a versão instalada do sdk que você tem instalada.&lt;/p&gt;

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

&lt;p&gt;Feito isso abra o Visual Studio e crie um novo projeto api web conforme o passo a passo abaixo.&lt;/p&gt;

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

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

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

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

&lt;p&gt;Abra esse projeto dentro do visual studio e ele ira ter a seguinte estrutura&lt;/p&gt;

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

&lt;p&gt;Antes de iniciarmos, ja vamos instalar dependencias que iremos utilizar em nossa aplicação que serão as seguintes&lt;/p&gt;

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

&lt;p&gt;Instale cada uma delas seguindo o passo a passo abaixo&lt;br&gt;
Clique botão direito na raiz da aplicação e entre em &lt;code&gt;Gerenciar pacotes do nuget&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fndt7psb2gy1s64a21g4f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fndt7psb2gy1s64a21g4f.png" alt="Image description" width="774" height="262"&gt;&lt;/a&gt;&lt;br&gt;
Na aba que ira abrir vá em &lt;code&gt;Procurar&lt;/code&gt; e digite cada dependencia acima para instalar ao projeto conforme abaixo&lt;/p&gt;

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

&lt;p&gt;Vamos estruturar nossa api utilizando o padrão de arquitetura ´Clean Architecture´ o que nos possibilita ter um sistema coeso e de baixo acoplamento, trabalhando a separação de responsabilidades ao nosso sistema,o que facilita a manutenabilidade de um sistema complexo e robusto. &lt;br&gt;
Para isso vamos ter 3 camadas em nossa api fazendo a separação da mesma nas seguintes estruturas.&lt;br&gt;
&lt;strong&gt;Domain&lt;/strong&gt; Estrutura que será o nosso core, ou seja o núcleo da nossa api, dentro dela era conter o domínio da nossa aplicação e essa camada não depende de nenhuma camada do nosso sistema.&lt;br&gt;
&lt;strong&gt;Application&lt;/strong&gt; Essa camada conterá os casos de usos da nossa aplicação, contendo os serviços que manipulara o nosso domínio para realizar as transações de nossa api.&lt;br&gt;
Observação: Essa camada depende da camada de domínio porem não pode ter nenhuma dependência com a camada seguinte.&lt;br&gt;
&lt;strong&gt;Infrastructure&lt;/strong&gt; Essa camada conterá toda parte de tecnologia/infraestrutura do nosso sistema e será a camada responsável por disponibilizar acesso externo a nossa api.&lt;br&gt;
Observação: Essa camada tem dependência com as outras duas camadas citadas.&lt;br&gt;
Vamos seguir com nossa api, vamos criar 3 pastas em nossa aplicação que ira simbolizar as camadas citadas acima, a estrutura do nosso sistema devera ficar conforme a imagem abaixo.&lt;/p&gt;

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

&lt;p&gt;Vamos iniciar nossa aplicação definindo nossa camada de &lt;code&gt;Domínio&lt;/code&gt;, vamos definir nossa entity &lt;code&gt;Employer&lt;/code&gt; conforme abaixo.&lt;br&gt;
&lt;strong&gt;Employer&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using FirstApi.Domain.ValueObjects;

namespace FirstApi.Domain.Entities
{
    public class Employer
    {
        public int Id { get; set; }
        public string? Nome { get; set; }
        public string? Cargo { get; set; }

        public Payment? Payment { get; set; }
        public double? PaymentTotal { get; set; }

        public void AddPaymentByPremiation(double premiation)
        {
            PaymentTotal = PaymentTotal + premiation;
        }
    }
}


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

&lt;/div&gt;



&lt;p&gt;**Observação: **Note que temos o método &lt;code&gt;addPaymentByPremiation&lt;/code&gt; em nossa entity, método e responsável por adicionar uma premiação ao pagamento do funcionário, ou seja, nossa classe de domínio não será anêmica.&lt;/p&gt;

&lt;p&gt;Vamos definir também em nossa camada de &lt;code&gt;Domínio&lt;/code&gt; uma interface com o contrato do nosso repositório ligado a entidade Employer e uma classe Payment que e um value-object da classe Employer.&lt;br&gt;
&lt;strong&gt;IEmployerRepository&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using FirstApi.Domain.Entities;

namespace FirstApi.Domain.Repositories
{
    public interface IEmployerRepository
    {
        Task&amp;lt;List&amp;lt;Employer&amp;gt;&amp;gt; FindEmployers();
        Task&amp;lt;Employer&amp;gt; FindEmployer(int id);
        Task&amp;lt;Employer&amp;gt; Register(Employer employer);
        Task&amp;lt;Employer&amp;gt; UpdateEmployer(Employer employer);
        void DeleteEmployer(Employer employer);
    }
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Payment&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;namespace FirstApi.Domain.ValueObjects
{
    public class Payment
    {
        public double Salary { get; set; }
        public double Benefits { get; set; }

        public double getPaymentTotal()
        {
            return Salary + Benefits;
        }
    }

}

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

&lt;/div&gt;



&lt;p&gt;A estrutura do nosso projeto agora ficou conforme a imagem abaixo, nossa camada de Domain é o núcleo da nossa api, portanto, ela não tem dependência com nenhuma outra camada do nosso sistema.&lt;/p&gt;

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

&lt;p&gt;Seguimos agora para a camada &lt;code&gt;Application&lt;/code&gt; que e a responsável pelos serviços e implementação da regra de negocio de nossa api, na &lt;em&gt;Clean Architecture&lt;/em&gt; utilizamos &lt;code&gt;UseCases&lt;/code&gt;,ou seja, casos de uso para implementar e realizar uma ação em nossa api, nessa ação definimos o que iremos receber de dados em nossa request para realizar a ação e o que vamos retornar após a ação realizada, isso nos da a facilidade para alterarmos, se necessário, tanto os dados de entrada como os de saída da nossa api tornando nossa aplicação resiliente a mudanças.&lt;br&gt;
Para não estender o artigo não vou seguir passo a passo mas o codigo dessa camada pode ser visualizado no &lt;a href="https://github.com/2020nani/dotnet-article/tree/master/Application/UseCases/CasesEmployer" rel="noopener noreferrer"&gt;repositorio&lt;/a&gt;&lt;br&gt;
Nossa camada de &lt;code&gt;Application&lt;/code&gt; sera implementado 4 casos de uso ligados a entity Employer e ficara implementado conforme abaixo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp7l1z9r7pbo6bbnywza7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp7l1z9r7pbo6bbnywza7.png" alt="Image description" width="433" height="602"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Observação:&lt;/strong&gt; Como já citamos antes essa camada tem dependência com a camada de &lt;code&gt;Domain&lt;/code&gt; pois utilizamos a entity &lt;code&gt;Employer&lt;/code&gt; e a interface &lt;code&gt;IEmployerRepository&lt;/code&gt; definida na camada de domínio que será implementada na camada mais externa da nossa aplicação, ou seja, a &lt;strong&gt;Infrastructure&lt;/strong&gt;.&lt;br&gt;
Para realizarmos a injeção da classe IEmployerRepository e dos services de cada casos de uso via construtor temos que adiciona-los ao escopo da nossa aplicação dentro da classe Program.cs, que ficara conforme abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using FirstApi.Application.UseCases.CasesEmployer.ConsultEmployer;
using FirstApi.Application.UseCases.CasesEmployer.DeleteEmployer;
using FirstApi.Application.UseCases.CasesEmployer.Register;
using FirstApi.Application.UseCases.CasesEmployer.UpdateEmployer;
using FirstApi.Domain.Repositories;
using FirstApi.Infrastructure.Data;
using FirstApi.Infrastructure.Handler;
using FirstApi.Infrastructure.Repositories;
using Microsoft.EntityFrameworkCore;

namespace FirstApi
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // Add services to the container.
            builder.Services.AddScoped&amp;lt;IEmployerRepository, EmployerRepository&amp;gt;();
            builder.Services.AddScoped&amp;lt;IRegisterEmployerService, RegisterEmployerService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IUpdateEmployerService, UpdateEmployerService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IConsultEmployerService, ConsultEmployerService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IDeleteEmployerService, DeleteEmployerService&amp;gt;();

            builder.Services.AddControllers();
            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();

            var app = builder.Build();

            // Configure the HTTP request pipeline.
            if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }

            app.UseHttpsRedirection();

            app.UseAuthorization();

            // global error handler
            app.UseMiddleware&amp;lt;GlobalExceptionHandler&amp;gt;();

            app.MapControllers();

            app.Run();
        }
    }
}
A classe EmployerRepository iremos construir na camada de Infrastructure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Após definirmos nossos &lt;code&gt;Usecases&lt;/code&gt; vamos seguir agora para a camada seguinte da nossa aplicação, a camada &lt;code&gt;Infrastructure&lt;/code&gt;, responsável pela parte tecnológica do nosso sistema e por disponibilizar acesso externo a nossa api, nessa camada fica as classes de Controllers, configurações banco de dados, implementações dos repositórios para acesso a transações no banco de dados, fluxo de mensagerias e etc...&lt;br&gt;
Vamos configurar agora a conexão ao nossa database postgres, vamos criar uma pasta &lt;code&gt;Data&lt;/code&gt; e dentro dela uma classe &lt;code&gt;SystemDbContext.cs&lt;/code&gt; que ira configurar um &lt;strong&gt;DbContext&lt;/strong&gt;, um tipo de ORM em dotnet.&lt;br&gt;
&lt;strong&gt;SystemDbContext&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using FirstApi.Domain.Entities;
using FirstApi.Infrastructure.Data.Map;
using Microsoft.EntityFrameworkCore;

namespace FirstApi.Infrastructure.Data
{
    public class SystemDbContext : DbContext
    {
        public SystemDbContext(DbContextOptions&amp;lt;SystemDbContext&amp;gt; options)
            : base(options)
        {

        }

        public DbSet&amp;lt;Employer&amp;gt; Employers { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.ApplyConfiguration(new EmployerMap());
            base.OnModelCreating(modelBuilder);
        }
    }
}

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

&lt;/div&gt;



&lt;p&gt;Dentro da pasta &lt;code&gt;Data&lt;/code&gt; crie uma nova pasta &lt;code&gt;Map&lt;/code&gt; e dentro dela uma classe &lt;code&gt;EmployerMap.cs&lt;/code&gt; que ira mapear a tabela Employer para ser criada em nosso database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore;
using FirstApi.Domain.Entities;

namespace FirstApi.Infrastructure.Data.Map
{
    public class EmployerMap : IEntityTypeConfiguration&amp;lt;Employer&amp;gt;
    {
        public void Configure(EntityTypeBuilder&amp;lt;Employer&amp;gt; builder)
        {
            builder.HasKey(x =&amp;gt; x.Id);
            builder.Property(x =&amp;gt; x.Nome).IsRequired().HasMaxLength(255);
            builder.Property(x =&amp;gt; x.Cargo).IsRequired().HasMaxLength(255);
            builder.Property(x =&amp;gt; x.PaymentTotal).IsRequired();
            builder.ToTable("Employers")
                .OwnsOne(x =&amp;gt; x.Payment, x =&amp;gt;
                {
                    x.Property(a =&amp;gt; a.Salary)
                    .HasColumnName("salary")
                    .IsRequired();
                    x.Property(a =&amp;gt; a.Benefits)
                    .HasColumnName("benefits")
                    .IsRequired()
                    .HasDefaultValue(0);
                });
        }
    }
}

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

&lt;/div&gt;



&lt;p&gt;Após isso temos que definir nossa string de conexão ao database no arquivo appsetings.Development.json que ficara assim.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "ConnectionStrings": {
    "DefaultConnection": "Host=localhost;Port=5433;Database=net;Username=admin;Password=password"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos configurar na classe main da nossa aplicação &lt;code&gt;Program.cs&lt;/code&gt; as configurações de acesso ao banco conforme abaixo.&lt;/p&gt;

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

&lt;p&gt;Agora vamos rodar dois comandos dentro do console Gerenciador de pacotes que ira criar uma migration e criar nossa tabela dentro do database.&lt;br&gt;
Va no console Gerenciador de pacotes que entre com o comando &lt;code&gt;Add-Migration InitialDB -Context SystemDbContext&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;Danto tudo certo, em seguida entre com o comando &lt;code&gt;Update-Database -Context SystemDbContext&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgywunk0sl7gytbu73g28.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgywunk0sl7gytbu73g28.png" alt="Image description" width="800" height="504"&gt;&lt;/a&gt;&lt;br&gt;
Crie uma pasta &lt;code&gt;Repositories&lt;/code&gt; e dentro dela a classe &lt;code&gt;EmployerRepository&lt;/code&gt; que ira implementar a classe &lt;code&gt;IEmployerRepository&lt;/code&gt; definida em nosso dominio.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;﻿using FirstApi.Domain.Entities;
using FirstApi.Domain.Repositories;
using FirstApi.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;

namespace FirstApi.Infrastructure.Repositories
{
    public class EmployerRepository : IEmployerRepository
    {
        private readonly SystemDbContext _Dbcontext;

        public EmployerRepository(SystemDbContext context)
        {
            _Dbcontext = context;
        }

        async Task&amp;lt;Employer&amp;gt; IEmployerRepository.Register(Employer employer)
        {
            await _Dbcontext.Employers.AddAsync(employer);
            _Dbcontext.SaveChanges();
            return employer;
        }

        async void IEmployerRepository.DeleteEmployer(Employer employer)
        {
            _Dbcontext.Employers.Remove(employer);
            await _Dbcontext.SaveChangesAsync();
        }

        async Task&amp;lt;Employer&amp;gt; IEmployerRepository.UpdateEmployer(Employer employer)
        {
            _Dbcontext.Employers.Update(employer);
            await _Dbcontext.SaveChangesAsync();
            return employer;
        }

        async Task&amp;lt;Employer&amp;gt; IEmployerRepository.FindEmployer(int id)
        {
            return await _Dbcontext.Employers.FirstOrDefaultAsync(u =&amp;gt; u.Id == id);
        }

        async Task&amp;lt;List&amp;lt;Employer&amp;gt;&amp;gt; IEmployerRepository.FindEmployers()
        {
            return await _Dbcontext.Employers.ToListAsync();
        }

    }
}

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

&lt;/div&gt;



&lt;p&gt;Crie agora uma pasta &lt;code&gt;Controllers&lt;/code&gt; e dentro a classe &lt;code&gt;EmployerController.cs&lt;/code&gt; que será a responsável por disponibilizar acesso externo a nossa api via chamadas Http e ficara conforme abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;﻿using FirstApi.Application.UseCases.CasesEmployer;
using FirstApi.Application.UseCases.CasesEmployer.ConsultEmployer;
using FirstApi.Application.UseCases.CasesEmployer.DeleteEmployer;
using FirstApi.Application.UseCases.CasesEmployer.Register;
using FirstApi.Application.UseCases.CasesEmployer.UpdateEmployer;
using FirstApi.Domain.Entities;
using Microsoft.AspNetCore.Mvc;

namespace FirstApi.Infrastructure.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class EmployerController
    {
        private  IRegisterEmployerService _registerService;
        private IUpdateEmployerService _updateService;
        private IConsultEmployerService _consultService;
        private IDeleteEmployerService _deleteService;

        public EmployerController(
            IRegisterEmployerService service,
            IUpdateEmployerService updateService,
            IConsultEmployerService consultService,
            IDeleteEmployerService deleteService)
        {
            _registerService = service;
            _updateService = updateService;
            _consultService = consultService;
            _deleteService = deleteService;
        }

        [HttpPost]
        public RegisterEmployerOutput Post([FromBody] RegisterEmployerInput input)
        {
            return _registerService.Execute(input);
        }

        [HttpPut]
        public UpdateEmployerOutput Put([FromBody] UpdateEmployerInput input)
        {
            return _updateService.Execute(input);
        }

        [HttpGet("{id}")]
        public ConsultEmployerOutput findEmployer(int id)
        {
            return _consultService.FindEmployerById(id);
        }

        [HttpGet]
        public List&amp;lt;ConsultEmployerOutput&amp;gt; findEmployers()
        {
            return _consultService.FindEmployers();
        }

        [HttpDelete("{id}")]
        public string Delete(int id)
        {
            return _deleteService.DeleteEmployer(id);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nossa camada &lt;code&gt;Infrastructure&lt;/code&gt; ficara assim.&lt;/p&gt;

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

&lt;p&gt;Crie um arquivo com o nome docke-compose.yaml na raiz do projeto, vamos configurar esse arquivo para subir um DB Postgres no docker.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '3'

services:

 postgres:
   image: 'postgres:alpine'
   volumes:
     - postgres-volume:/var/lib/postgresql/data
   ports:
     - 5433:5432
   environment:
     POSTGRES_USER: admin
     POSTGRES_PASSWORD: password
     POSTGRES_DB: net
volumes:
  postgres-volume:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na pasta raiz rode o comando docker-compose up -d conforme abaixo para subir o database no docker.&lt;/p&gt;

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

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

&lt;p&gt;Vamos rodar nossa aplicação clicando nesse botao que fica na parte de cima do visual studio&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9xifj65v3u88ai9phd00.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9xifj65v3u88ai9phd00.png" alt="Image description" width="162" height="74"&gt;&lt;/a&gt;&lt;br&gt;
E já podemos ver o swagger da nossa aplicação.&lt;/p&gt;

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

&lt;p&gt;Vamos testar nossa aplicação, primeiro vou realizar um registro&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvz0nxldbe17da08tfb1v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvz0nxldbe17da08tfb1v.png" alt="Image description" width="800" height="408"&gt;&lt;/a&gt;&lt;br&gt;
 Agora vou buscar esse registro pelo Id&lt;/p&gt;

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

&lt;p&gt;Para seguirmos o projeto vamos ter a segunda parte desse artigo, onde vamos criar um fluxo para salvar um usuário obtendo seus dados de Endereço através de uma integração da nossa api com a api &lt;strong&gt;ViaCep&lt;/strong&gt;, ate la.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/2020nani/api-rest-net-completa-com-jwttoken-integracao-com-api-viacep-utilizando-padrao-de-arquitetura-clean-architecture-parte-2-im"&gt;Parte 2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/nanialmeida/" rel="noopener noreferrer"&gt;linkedin&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/2020nani" rel="noopener noreferrer"&gt;github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>restapi</category>
      <category>csharp</category>
      <category>security</category>
    </item>
    <item>
      <title>Api Rest .Net completa com JwtToken integração com api ViaCep utilizando padrão de arquitetura clean architecture - parte 2</title>
      <dc:creator>Hernani Almeida</dc:creator>
      <pubDate>Sat, 27 Jul 2024 01:47:48 +0000</pubDate>
      <link>https://dev.to/2020nani/api-rest-net-completa-com-jwttoken-integracao-com-api-viacep-utilizando-padrao-de-arquitetura-clean-architecture-parte-2-im</link>
      <guid>https://dev.to/2020nani/api-rest-net-completa-com-jwttoken-integracao-com-api-viacep-utilizando-padrao-de-arquitetura-clean-architecture-parte-2-im</guid>
      <description>&lt;p&gt;Ferramentas necessárias:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dotnet.microsoft.com/pt-br/download/visual-studio-sdks" rel="noopener noreferrer"&gt;Sdk .net&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/desktop/windows/install/#:~:text=%20Install%20Docker%20Desktop%20on%20Windows%20%F0%9F%94%97%20,to%20authorize%20the%20installer%20and%20proceed...%20More%20" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://visualstudio.microsoft.com/pt-br/vs/community/" rel="noopener noreferrer"&gt;Visual Studio Community&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/2020nani/api-rest-net-completa-com-jwttoken-e-integracao-com-api-viacep-utilizando-padrao-de-arquitetura-clean-architecture-5b1n"&gt;Ter completado o crud da api mostrado no artigo anterior&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Seguimos com a construção da nossa api, neste artigo vamos estruturar nossa api para salvar um usuário integrando com a api &lt;code&gt;ViaCep&lt;/code&gt; para buscar os dados de endereço desse usuário através do Cep.&lt;br&gt;
Vamos criar estrutura para salvar um usuário, vamos criar a entity &lt;code&gt;User&lt;/code&gt; que ira conter os dados de endereço do usuário através da classe &lt;code&gt;Endereco&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;User&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using FirstApi.Domain.ValueObjects;
using FirstApi.Infrastructure.Integration.ViaCep;

namespace FirstApi.Domain.Entities
{
    public class User
    {
        public int Id { get; set; }
        public string? Name { get; set; }
        public string? Email { get; set; }
        public string? Password { get; set; }
        public Endereco? Endereco { get; set; }

        public Endereco GetEndereco(ViaCepResponse response)
        {
            Endereco endereco = new Endereco();
            if(response is null)
            {
                return endereco;
            }
            endereco.Complemento = response.Complemento;
            endereco.Cep = response.Cep;
            endereco.Bairro = response.Bairro;
            endereco.Logradouro = response.Logradouro;
            endereco.Localidade = response.Localidade;
            endereco.Cep = response.Cep;
            endereco.Unidade = response.Unidade;
            endereco.Uf = response.Uf;
            return endereco;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Endereco&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using FirstApi.Infrastructure.Integration.ViaCep;

namespace FirstApi.Domain.ValueObjects
{
    public class Endereco
    {
        public string? Cep { get; set; }
        public string? Logradouro { get; set; }
        public string? Complemento { get; set; }
        public string? Unidade { get; set; }
        public string? Bairro { get; set; }
        public string? Localidade { get; set; }
        public string? Uf { get; set; }

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

&lt;/div&gt;



&lt;p&gt;A estrutura vamos seguir a mesma que a &lt;a href="https://dev.tolink"&gt;parte 1 desse artigo&lt;/a&gt;, ou se preferir pode visitar o &lt;a href="https://github.com/2020nani/dotnet-article/tree/master" rel="noopener noreferrer"&gt;repositorio&lt;/a&gt; contendo o código para usar como referencia.&lt;br&gt;
Na classe de entrada de dados para registrar nosso usuário vamos receber um parâmetro &lt;code&gt;Cep&lt;/code&gt;, através desse parâmetro vamos realizar uma chamada para a api &lt;code&gt;ViaCep&lt;/code&gt; para preencher os dados de endereço do usuário, vamos utilizar a lib &lt;code&gt;Refit&lt;/code&gt; para realizar essa integração.&lt;br&gt;
Conforme vimos no artigo anterior vamos instalar essas duas dependências no projeto.&lt;/p&gt;

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

&lt;p&gt;Feito isso, seguindo o padrão da &lt;code&gt;Clean Architecture&lt;/code&gt; na camada de &lt;strong&gt;Infrastructure&lt;/strong&gt; vamos criar uma pasta Integration e a seguinte estrutura dentro dela.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;ViaCepResponse&lt;/strong&gt; classe que mapeara o response oriundo da api ViaCep&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;namespace FirstApi.Infrastructure.Integration.ViaCep
{
    public class ViaCepResponse
    { 
        public string? Cep { get; set; }
        public string? Logradouro { get; set; }
        public string? Complemento { get; set; }
        public string? Unidade { get; set; }
        public string? Bairro { get; set; }
        public string? Localidade { get; set; }
        public string? Uf {  get; set; }

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;IViaCepIntegrationRefit&lt;/strong&gt; classe onde configuramos o client de acesso ao endpoint da api ViaCep&lt;br&gt;
&lt;/p&gt;

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

namespace FirstApi.Infrastructure.Integration.ViaCep.Refit
{
    public interface IViaCepIntegrationRefit
    {
        [Get("/ws/{cep}/json/")]
        public Task&amp;lt;ApiResponse&amp;lt;ViaCepResponse&amp;gt;&amp;gt; FindEnderecoByCep(string cep);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;IViaCepIntegrationService&lt;/strong&gt; contrato do serviço que utilizara o client para realizar a chamada em nossa logica.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;namespace FirstApi.Infrastructure.Integration.ViaCep
{
    public interface IViaCepIntegrationService
    {
        public Task&amp;lt;ViaCepResponse&amp;gt; FindEnderecoByCep(string cep);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ViaCepIntegrationService&lt;/strong&gt; serviço que implementa o serviço para buscar os dados de Endereço do usuário.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
using FirstApi.Infrastructure.CustomException;
using FirstApi.Infrastructure.Integration.ViaCep.Refit;

namespace FirstApi.Infrastructure.Integration.ViaCep
{
    public class ViaCepIntegrationService : IViaCepIntegrationService
    {
        private readonly IViaCepIntegrationRefit _refit;

        public ViaCepIntegrationService(IViaCepIntegrationRefit refit)
        {
            _refit = refit;
        }

        async Task&amp;lt;ViaCepResponse&amp;gt; IViaCepIntegrationService.FindEnderecoByCep(string cep)
        {
            var responseData = await _refit.FindEnderecoByCep(cep);
            if(responseData is null || !responseData.IsSuccessStatusCode)
            {
                throw new AppException("Error on integration with extern api");
            }

            return responseData.Content;
        }
    }
}

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

&lt;/div&gt;



&lt;p&gt;Vamos agora adicionar o escopo de cada serviço na nossa classe &lt;code&gt;Program.cs&lt;/code&gt;, para podermos realizar a injeção de dependência, e configurar o RefitClient também em nossa classe &lt;code&gt;Program.cs&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;Nossa classe &lt;code&gt;Program.cs&lt;/code&gt; ficara assim.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
using FirstApi.Application.UseCases.CasesEmployer.ConsultEmployer;
using FirstApi.Application.UseCases.CasesEmployer.DeleteEmployer;
using FirstApi.Application.UseCases.CasesEmployer.Register;
using FirstApi.Application.UseCases.CasesEmployer.UpdateEmployer;
using FirstApi.Application.UseCases.CasesUser.ConsultUser;
using FirstApi.Application.UseCases.CasesUser.DeleteUser;
using FirstApi.Application.UseCases.CasesUser.RegisterUser;
using FirstApi.Application.UseCases.CasesUser.UpdateUser;
using FirstApi.Application.UseCases.PasswordHasher;
using FirstApi.Domain.Repositories;
using FirstApi.Infrastructure.Data;
using FirstApi.Infrastructure.Handler;
using FirstApi.Infrastructure.Integration.ViaCep;
using FirstApi.Infrastructure.Integration.ViaCep.Refit;
using FirstApi.Infrastructure.Repositories;
using Microsoft.EntityFrameworkCore;
using Refit;

namespace FirstApi
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);
            // Configure logging
            builder.Logging.ClearProviders();
            builder.Logging.AddConsole();
            builder.Logging.AddDebug();
            // Configure data base access
            builder.Services.AddDbContext&amp;lt;SystemDbContext&amp;gt;(
                options =&amp;gt; options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
            // Add repositories to the container.
            builder.Services.AddScoped&amp;lt;IEmployerRepository, EmployerRepository&amp;gt;();
            builder.Services.AddScoped&amp;lt;IUserRepository, UserRepository&amp;gt;();
            // Add services to the container.
            // employer
            builder.Services.AddScoped&amp;lt;IRegisterEmployerService, RegisterEmployerService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IUpdateEmployerService, UpdateEmployerService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IConsultEmployerService, ConsultEmployerService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IDeleteEmployerService, DeleteEmployerService&amp;gt;();
            // user
            builder.Services.AddScoped&amp;lt;IRegisterUserService, RegisterUserService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IUpdateUserService, UpdateUserService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IConsultUserService, ConsultUserService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IDeleteUserService, DeleteUserService&amp;gt;();
            builder.Services.AddScoped&amp;lt;IPasswordHasher, PasswordHasher&amp;gt;();
            // client viacep
            builder.Services.AddScoped&amp;lt;IViaCepIntegrationService, ViaCepIntegrationService&amp;gt;();
            // Add client refit
            builder.Services.AddRefitClient&amp;lt;IViaCepIntegrationRefit&amp;gt;().ConfigureHttpClient(c =&amp;gt;
            {
                c.BaseAddress = new Uri("https://viacep.com.br");
            }
            );

            builder.Services.AddControllers();
            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();

            var app = builder.Build();

            // Configure the HTTP request pipeline.
            if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }

            app.UseHttpsRedirection();

            app.UseAuthorization();

            // global error handler
            app.UseMiddleware&amp;lt;GlobalExceptionHandler&amp;gt;();

            app.MapControllers();

            app.Run();
        }
    }
}

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

&lt;/div&gt;



&lt;p&gt;Dentro do nosso &lt;code&gt;UserController&lt;/code&gt; chamamos a api ViaCep para popularmos nosso objeto ViaCepResponse, que e passada como parâmetro para nosso serviço junto com o input de entrada de dados.&lt;/p&gt;

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

&lt;p&gt;Dentro do nosso serviço utilizamos o método &lt;code&gt;Convert&lt;/code&gt; implementado dentro da nossa classe de entrada de dados, seguindo o conceito de não termos classes anêmicas em nosso projeto, que ira retornar um objeto &lt;code&gt;User&lt;/code&gt;.&lt;/p&gt;

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

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

&lt;p&gt;Lembre-se de seguir o passo a passo do &lt;a href="https://dev.tolink"&gt;artigo 1&lt;/a&gt; pois será necessário mapear a entity &lt;code&gt;User&lt;/code&gt; e criar a tabela &lt;code&gt;Users&lt;/code&gt; no nosso database, feito isso tudo já esta pronto para testarmos nossa api.&lt;/p&gt;

&lt;p&gt;Requisição POST&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffqrg24yct6dyo1zceran.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffqrg24yct6dyo1zceran.png" alt="Image description" width="800" height="371"&gt;&lt;/a&gt;&lt;br&gt;
Retorno da Api com os dados completos do usuário, inclusive endereço&lt;/p&gt;

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

&lt;p&gt;Registro salvo banco de dados.&lt;/p&gt;

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

&lt;p&gt;Na próxima parte vamos implementar a parte de segurança da nossa api utilizando o JWt Token, ate lá.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/2020nani/api-rest-net-completa-com-jwttoken-integracao-com-api-viacep-utilizando-padrao-de-arquitetura-clean-architecture-parte-3-21o9"&gt;Parte 3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/nanialmeida/" rel="noopener noreferrer"&gt;linkedin&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/2020nani" rel="noopener noreferrer"&gt;github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>cleancode</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Saga Pattern in Microservices</title>
      <dc:creator>Hernani Almeida</dc:creator>
      <pubDate>Tue, 12 Mar 2024 02:15:36 +0000</pubDate>
      <link>https://dev.to/2020nani/saga-pattern-in-microservices-3h6i</link>
      <guid>https://dev.to/2020nani/saga-pattern-in-microservices-3h6i</guid>
      <description>&lt;p&gt;Neste post vamos desmistificar o design do padrão saga, vamos construir um sistema de microsserviços que estará salvando dados completos do usuário onde usaremos o &lt;strong&gt;Orchestration Saga Pattern&lt;/strong&gt;, abaixo vemos o fluxograma do projeto.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;UserService&lt;/strong&gt; - Essa API (Java) ira receber a requisição via rest http de um cadastro de usuário e produzir uma mensagem em um tópico &lt;strong&gt;Kafka&lt;/strong&gt; para que a mesma seja consumida pela aplicação orquestradora.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Orchestrator&lt;/strong&gt; - Essa API (Java) recebe a mensagem produzida pela API acima através de um Listener de um tópico KAFKA que estará captando as mensagem produzidas por este tópico e realiza a orquestração de todo fluxo da transação para os serviços seguintes atraves da &lt;strong&gt;(Events-Driven Architecture)&lt;/strong&gt;, ou seja via eventos, para garantir o sucesso da transação e o rolback da mesma caso exista alguma falha.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AdressService&lt;/strong&gt; - Essa API (Java - Webflux) recebe a mensagem produzida pela API Orchestrator pelo listener do tópico kafka e através do cep passado na requisição faz uma integração via webclient &lt;strong&gt;(Api de Data que iremos construir utilizando nodejs(Graphql)&lt;/strong&gt; para buscar o endereço desse usuário e adicionar esses dados na transação.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ValidatedService&lt;/strong&gt; - Essa API (Kotlin) recebe a mensagem produzida pela API Orchestrator pelo listener do tópico kafka e valida se o cpf do usuário esta apto para ser cadastrado através da api de Data construida em graphql.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;UserRegistration&lt;/strong&gt; - Essa API (Kotlin) recebe a mensagem produzida pela API Orchestrator pelo listener do tópico kafka e persiste os dados completos do usuario no banco de dados.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DataService&lt;/strong&gt; - Essa API (Nodejs/Graphql) ira nos fornecer dados relacionados ao usuário, como endereço a partir do cep e validar se o documento passado na requisição não esta numa lista de documentos bloqueados.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nesse artigo vamos utilizar o &lt;strong&gt;Saga Pattern Orchestration&lt;/strong&gt;, que consiste em ter um microsserviço orquestrador para garantir a execução com sucesso ou rollback dessa transação garantindo sua &lt;strong&gt;atomicidade&lt;/strong&gt;. Há também o &lt;strong&gt;Saga Pattern Choreography&lt;/strong&gt; que pretendo fazer outro post para aprendermos juntos sobre ele.&lt;/p&gt;

&lt;p&gt;Vamos utilizar apis em Java, Kotlin e nodejs(graphql) para deixar essas integrações mais interessante e demonstrar o poder do conceito de microsservices, onde podemos ter aplicações de varias linguagens se integrando uma com as outras, bora la que vai ser bem bacana.&lt;/p&gt;

&lt;p&gt;OBS: Esse fluxo partiu da minha ideia e de longe não seria necessário utilizar o Saga Pattern, porem este artigo tem a finalidade de entendermos melhor o funcionamento e o conceito dessa ferramenta em microsserviços.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/2020nani/saga-pattern-in-microservices-parte-2-122e"&gt;Parte 2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/nanialmeida/" rel="noopener noreferrer"&gt;linkedin&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/2020nani" rel="noopener noreferrer"&gt;github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>java</category>
      <category>kotlin</category>
      <category>node</category>
    </item>
    <item>
      <title>Saga Pattern in Microservices - Parte 2</title>
      <dc:creator>Hernani Almeida</dc:creator>
      <pubDate>Tue, 12 Mar 2024 02:11:35 +0000</pubDate>
      <link>https://dev.to/2020nani/saga-pattern-in-microservices-parte-2-122e</link>
      <guid>https://dev.to/2020nani/saga-pattern-in-microservices-parte-2-122e</guid>
      <description>&lt;p&gt;Ferramentas necessárias:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.oracle.com/java/technologies/downloads/" rel="noopener noreferrer"&gt;Java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/desktop/windows/install/#:~:text=%20Install%20Docker%20Desktop%20on%20Windows%20%F0%9F%94%97%20,to%20authorize%20the%20installer%20and%20proceed...%20More%20" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;IDE de sua preferencia&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para iniciarmos nossa aplicação, será necessário preparar o ambiente local para termos acessos as tecnologias utilizadas, vamos utilizar a magia do &lt;strong&gt;Docker&lt;/strong&gt; e rodar o kafka, mongodb e postgres.&lt;br&gt;
Crie uma pasta com o nome a seu gosto e dentro da mesma crie um arquivo com o nome &lt;strong&gt;docker-compose.yaml&lt;/strong&gt; e dentro deste arquivo copie o seguinte codigo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '3'

services:

  user-db:
    image: mongo:latest
    container_name: user-db
    restart: always
    networks:
      - orchestrator-saga
    environment:
      - MONGO_INITDB_ROOT_USERNAME=admin
      - MONGO_INITDB_ROOT_PASSWORD=123456
    ports:
      - 27017:27017

  adress-db:
    image: 'postgres:alpine'
    container_name: adress-db
    volumes:
      - adress-volume:/var/lib/postgresql/data
    ports:
      - 5433:5432
    environment:
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: password
      POSTGRES_DB: adress-db
      POSTGRES_HOST: adress-db
    networks:
      - orchestrator-saga

  userregistration-db:
    image: 'postgres:alpine'
    container_name: userregistration-db
    volumes:
      - userregistration-volume:/var/lib/postgresql/data
    ports:
      - 5434:5432
    environment:
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: password
      POSTGRES_DB: userregistration-db
      POSTGRES_HOST: userregistration-db
    networks:
      - orchestrator-saga

  zookeeper:
    image: confluentinc/cp-zookeeper:latest
    networks:
      - orchestrator-saga
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000
    ports:
      - 22181:2181

  kafka:
    image: confluentinc/cp-kafka:latest
    container_name: kafka
    depends_on:
      - zookeeper
    restart: "no"
    ports:
      - "2181:2181"
      - "9092:9092"
    networks:
      - orchestrator-saga
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1

  redpanda-console:
    container_name: redpanda
    image: docker.redpanda.com/vectorized/console:latest
    restart: on-failure
    entrypoint: /bin/sh
    command: -c "echo \"$$CONSOLE_CONFIG_FILE\" &amp;gt; /tmp/config.yml; /app/console"
    ports:
      - "8087:8087"
    networks:
      - orchestrator-saga
    environment:
      CONFIG_FILEPATH: /tmp/config.yml
      CONSOLE_CONFIG_FILE: |
        kafka:
          brokers: ["kafka:29092"]
    depends_on:
      - "kafka"

volumes:
  adress-volume:
  userregistration-volume:

networks:
  orchestrator-saga:
    driver: bridge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora dentro da pasta execute o seguinte comando &lt;strong&gt;docker-compose up -d&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Dentro da interface visual do docker você devera visualizar os containers rodando para cada tecnologia que utilizaremos.&lt;/p&gt;

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

&lt;p&gt;Agora vamos utilizar o spring starter para criar nossa primeira estrutura de API.&lt;/p&gt;

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

&lt;p&gt;Vamos adicionar uma nova lib no nosso arquivo pom.xml para que seja gerado automaticamente a documentação via swagger da nossa api.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-starter-webmvc-ui --&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.springdoc&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;springdoc-openapi-starter-webmvc-ui&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;2.0.4&amp;lt;/version&amp;gt;
        &amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feito isso, vamos configurar nosso tópicos kafka e acesso ao mongoDb através do arquivo de properties da aplicação, defina o arquivo de application.properties igual o código abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server.port=3000

spring.kafka.bootstrap-servers=${KAFKA_BROKER:localhost:9092}
spring.kafka.topic.start-saga=start-saga
spring.kafka.topic.notify-ending=notify-ending
spring.kafka.consumer.group-id=user-group
spring.kafka.consumer.auto-offset-reset=latest

spring.data.mongodb.database=admin
spring.data.mongodb.uri=${MONGO_DB_URI:mongodb://admin:123456@localhost:27017}

logging.level.org.apache.kafka=OFF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;para configurar nosso topico Kafka vamos criar uma classe de configuração contendo as seguintes config.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package br.com.userservice.infrastructure.kafka;

import lombok.RequiredArgsConstructor;
import org.apache.kafka.clients.admin.NewTopic;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.apache.kafka.common.serialization.StringSerializer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.annotation.EnableKafka;
import org.springframework.kafka.config.TopicBuilder;
import org.springframework.kafka.core.*;

import java.util.HashMap;
import java.util.Map;

@EnableKafka
@Configuration
@RequiredArgsConstructor
public class KafkaConfig {

    private static final Integer PARTITION_COUNT = 1;
    private static final Integer REPLICA_COUNT = 1;

    @Value("${spring.kafka.bootstrap-servers}")
    private String bootstrapServers;

    @Value("${spring.kafka.consumer.group-id}")
    private String groupId;

    @Value("${spring.kafka.consumer.auto-offset-reset}")
    private String autoOffsetReset;

    @Value("${spring.kafka.topic.start-saga}")
    private String startSagaTopic;

    @Value("${spring.kafka.topic.notify-ending}")
    private String notifyEndingTopic;

    @Bean
    public ConsumerFactory&amp;lt;String, String&amp;gt; consumerFactory() {
        return new DefaultKafkaConsumerFactory&amp;lt;&amp;gt;(consumerProps());
    }

    private Map&amp;lt;String, Object&amp;gt; consumerProps() {
        var props = new HashMap&amp;lt;String, Object&amp;gt;();
        props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
        props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);
        props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, autoOffsetReset);
        return props;
    }

    @Bean
    public ProducerFactory&amp;lt;String, String&amp;gt; producerFactory() {
        return new DefaultKafkaProducerFactory&amp;lt;&amp;gt;(producerProps());
    }

    private Map&amp;lt;String, Object&amp;gt; producerProps() {
        var props = new HashMap&amp;lt;String, Object&amp;gt;();
        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
        props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        return props;
    }

    @Bean
    public KafkaTemplate&amp;lt;String, String&amp;gt; kafkaTemplate(ProducerFactory&amp;lt;String, String&amp;gt; producerFactory) {
        return new KafkaTemplate&amp;lt;&amp;gt;(producerFactory);
    }

    private NewTopic buildTopic(String name) {
        return TopicBuilder
                .name(name)
                .partitions(PARTITION_COUNT)
                .replicas(REPLICA_COUNT)
                .build();
    }

    @Bean
    public NewTopic startSagaTopic() {
        return buildTopic(startSagaTopic);
    }

    @Bean
    public NewTopic notifyEndingTopic() {
        return buildTopic(notifyEndingTopic);
    }
}

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

&lt;/div&gt;



&lt;p&gt;Após isto criamos uma classe controller que ira receber a requisição via http e chamar uma classe service para enviar uma mensagem com dados para nosso servico &lt;strong&gt;Orchestrator&lt;/strong&gt; que ira start/comandar/finalizar todo resto de envio de mensagens via topico Kafka para finalizar a transação de salvar um usuário.&lt;/p&gt;

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

&lt;p&gt;Uma classe Service que ira agregar/gerir a regra de negocio relacionada a transação, nesse caso enviar a mensagem com os dados para o serviço de orquestração.&lt;/p&gt;

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

&lt;p&gt;O codigo dessa aplicação ficara assim.&lt;br&gt;
&lt;a href="https://github.com/2020nani/saga_pattern/tree/master/user-service" rel="noopener noreferrer"&gt;API Saga Pattern - User Service&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/2020nani/saga-pattern-in-microservices-parte-3-3i73"&gt;Parte 3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/nanialmeida/" rel="noopener noreferrer"&gt;linkedin&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/2020nani" rel="noopener noreferrer"&gt;github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>java</category>
      <category>microservices</category>
      <category>kafka</category>
    </item>
    <item>
      <title>Saga Pattern in Microservices - Parte 3</title>
      <dc:creator>Hernani Almeida</dc:creator>
      <pubDate>Tue, 12 Mar 2024 02:10:42 +0000</pubDate>
      <link>https://dev.to/2020nani/saga-pattern-in-microservices-parte-3-3i73</link>
      <guid>https://dev.to/2020nani/saga-pattern-in-microservices-parte-3-3i73</guid>
      <description>&lt;p&gt;Ferramentas necessárias:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.oracle.com/java/technologies/downloads/" rel="noopener noreferrer"&gt;Java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/desktop/windows/install/#:~:text=%20Install%20Docker%20Desktop%20on%20Windows%20%F0%9F%94%97%20,to%20authorize%20the%20installer%20and%20proceed...%20More%20" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;IDE de sua preferencia&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/2020nani/teste-16oa-temp-slug-8201349?preview=92424408771c77939281b5ffdd2520e8e738ea34aa40fabb79b714d7e861f958d9a6a4c22310af4b7b3d96e4501163c596956f0aaedb6365c2ec2f3e"&gt;Configuração do ambiente conforme a parte 2 do artigo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vamos criar uma aplicação com o nome de &lt;strong&gt;Orchestrator&lt;/strong&gt; no &lt;a href="https://start.spring.io/" rel="noopener noreferrer"&gt;spring starter&lt;/a&gt; com as seguintes dependências necessárias&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc48yhvloazq317p2s21p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc48yhvloazq317p2s21p.png" alt="Image description" width="800" height="406"&gt;&lt;/a&gt;&lt;br&gt;
Essa api realizara todo o controle de eventos da nossa transação de cadastro de usuário através da &lt;strong&gt;(Events-Driven Architecture)&lt;/strong&gt;, nela ira conter a logica de envio de mensagens para seguir com a saga de cadastrar usuário ou para finalizar/realizar rolback conforme os tópicos de cada aplicação.&lt;br&gt;
Conforme a api anterior nessa api teremos o &lt;strong&gt;application.yml&lt;/strong&gt; contendo as configs do tópico kafka e também a classe de configuração do Kafka e tópicos.&lt;br&gt;
A saga e iniciada na api orquestradora através de um listener do kafka que recebe a mensagem enviada pela api &lt;strong&gt;User-Service&lt;/strong&gt;, nessa classe &lt;strong&gt;SagaOrchestratorConsumer&lt;/strong&gt; também estão configurados os listeners que continua a saga e que finalizam a saga com sucesso ou falha.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package br.com.orchestrator.application.consumer;

import br.com.orchestrator.core.service.OrchestrationService;
import br.com.orchestrator.core.utils.JsonUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@AllArgsConstructor
public class SagaOrchestratorConsumer {

    private final OrchestrationService service;
    private final JsonUtil jsonUtil;

    @KafkaListener(
        groupId = "${spring.kafka.consumer.group-id}",
        topics = "${spring.kafka.topic.start-saga}"
    )
    public void consumeStartSagaEvent(String payload) {
        log.info("Receiving event {} from start-saga topic", payload);
        var event = jsonUtil.toEvent(payload);
        service.startSaga(event);
    }

    @KafkaListener(
        groupId = "${spring.kafka.consumer.group-id}",
        topics = "${spring.kafka.topic.orchestrator}"
    )
    public void consumeOrchestratorEvent(String payload) {
        log.info("Receiving event {} from orchestrator topic", payload);
        var event = jsonUtil.toEvent(payload);
        service.continueSaga(event);
    }

    @KafkaListener(
        groupId = "${spring.kafka.consumer.group-id}",
        topics = "${spring.kafka.topic.finish-success}"
    )
    public void consumeFinishSagaSuccessEvent(String payload) {
        log.info("Receiving event {} from finish-success topic", payload);
        var event = jsonUtil.toEvent(payload);
        service.finishSagaSuccess(event);
    }

    @KafkaListener(
        groupId = "${spring.kafka.consumer.group-id}",
        topics = "${spring.kafka.topic.finish-fail}"
    )
    public void consumeFinishSagaFailEvent(String payload) {
        log.info("Receiving event {} from finish-fail topic", payload);
        var event = jsonUtil.toEvent(payload);
        service.finishSagaFail(event);
    }
}

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

&lt;/div&gt;



&lt;p&gt;Após receber a mensagem chamamos nosso service conforme a regra de negocio recebida via tópico kafka que utiliza a classe &lt;strong&gt;SagaExecutionController&lt;/strong&gt; para seguir com o fluxo da saga via event driven conforme veremos logo mais abaixo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package br.com.orchestrator.core.service;

import br.com.orchestrator.application.dto.Event;
import br.com.orchestrator.application.dto.History;
import br.com.orchestrator.application.producer.SagaOrchestratorProducer;
import br.com.orchestrator.application.saga.SagaExecutionController;
import br.com.orchestrator.core.enums.ETopics;
import br.com.orchestrator.core.utils.JsonUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

import static br.com.orchestrator.core.enums.EEventSource.ORCHESTRATOR;
import static br.com.orchestrator.core.enums.ESagaStatus.FAIL;
import static br.com.orchestrator.core.enums.ESagaStatus.SUCCESS;

@Slf4j
@Service
@AllArgsConstructor
public class OrchestrationService {

    private final SagaOrchestratorProducer producer;
    private final JsonUtil jsonUtil;
    private final SagaExecutionController sagaExecutionController;

    public void startSaga(Event event) {
        event.setSource(ORCHESTRATOR);
        event.setStatus(SUCCESS);
        var topic = getTopic(event);
        log.info("SAGA STARTED!");
        addHistory(event, "Saga started!");
        sendToProducerWithTopic(event, topic);
    }

    public void finishSagaSuccess(Event event) {
        event.setSource(ORCHESTRATOR);
        event.setStatus(SUCCESS);
        log.info("SAGA FINISHED SUCCESSFULLY FOR EVENT {}!", event.getId());
        addHistory(event, "Saga finished successfully!");
        notifyFinishedSaga(event);
    }

    public void finishSagaFail(Event event) {
        event.setSource(ORCHESTRATOR);
        event.setStatus(FAIL);
        log.info("SAGA FINISHED WITH ERRORS FOR EVENT {}!", event.getId());
        addHistory(event, "Saga finished with errors!");
        notifyFinishedSaga(event);
    }

    public void continueSaga(Event event) {
        var topic = getTopic(event);
        log.info("SAGA CONTINUING FOR EVENT {}", event.getId());
        sendToProducerWithTopic(event, topic);
    }

    private ETopics getTopic(Event event) {
        return sagaExecutionController.getNextTopic(event);
    }

    private void addHistory(Event event, String message) {
        var history = new History(event.getSource(), event.getStatus(), message, LocalDateTime.now());
        event.addToHistory(history);
    }

    private void sendToProducerWithTopic(Event event, ETopics topic) {
        producer.sendEvent(jsonUtil.toJson(event), topic.getTopic());
    }

    private void notifyFinishedSaga(Event event) {
        producer.sendEvent(jsonUtil.toJson(event), ETopics.NOTIFY_ENDING.getTopic());
    }
}

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

&lt;/div&gt;



&lt;p&gt;Nessa api teremos uma classe &lt;strong&gt;SagaHandler&lt;/strong&gt; que terá um método estático que retornara um vetor de uma matriz, utilizaremos essa matriz para que a api orquestradora entenda qual tópico ira enviar a mensagem para dar seguimento a saga de cadastro de usuário.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package br.com.orchestrator.application.saga;


import static br.com.orchestrator.core.enums.EEventSource.*;
import static br.com.orchestrator.core.enums.ESagaStatus.*;
import static br.com.orchestrator.core.enums.ETopics.*;

public final class SagaHandler {

    private SagaHandler() {

    }

    public static final Object[][] SAGA_HANDLER = {
        { ORCHESTRATOR, SUCCESS, ADRESS_VALIDATION_SUCCESS },
        { ORCHESTRATOR, FAIL, FINISH_FAIL },

        { ADRESS_VALIDATION_SERVICE, ROLLBACK_PENDING, ADRESS_VALIDATION_FAIL },
        { ADRESS_VALIDATION_SERVICE, FAIL, FINISH_FAIL },
        { ADRESS_VALIDATION_SERVICE, SUCCESS, VALIDATED_SUCCESS },

        { VALIDATED_SERVICE, ROLLBACK_PENDING, VALIDATED_FAIL },
        { VALIDATED_SERVICE, FAIL, ADRESS_VALIDATION_FAIL },
        { VALIDATED_SERVICE, SUCCESS, REGISTRATION_SUCCESS },

        { REGISTRATION_SERVICE, ROLLBACK_PENDING, REGISTRATION_FAIL },
        { REGISTRATION_SERVICE, FAIL, REGISTRATION_FAIL },
        { REGISTRATION_SERVICE, SUCCESS, FINISH_SUCCESS }
    };

    public static final int EVENT_SOURCE_INDEX = 0;
    public static final int SAGA_STATUS_INDEX = 1;
    public static final int TOPIC_INDEX = 2;
}

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

&lt;/div&gt;



&lt;p&gt;Criaremos uma classe &lt;strong&gt;SagaExecutionController&lt;/strong&gt; que ira ser utilizada para controlar toda a execução da saga, nesta classe que utilizamos a matriz acima para saber qual tópico kafka será enviada a mensagem para seguir saga.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package br.com.orchestrator.application.saga;

import br.com.orchestrator.application.dto.Event;
import br.com.orchestrator.application.exception.ValidationException;
import br.com.orchestrator.core.enums.ETopics;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Arrays;

import static br.com.orchestrator.application.saga.SagaHandler.*;
import static java.lang.String.format;
import static org.springframework.util.ObjectUtils.isEmpty;

@Slf4j
@Component
@AllArgsConstructor
public class SagaExecutionController {

    private static final String SAGA_LOG_ID = "USER ID: %s | TRANSACTION ID %s | EVENT ID %s";

    public ETopics getNextTopic(Event event) {
        if (isEmpty(event.getSource()) || isEmpty(event.getStatus())) {
            throw new ValidationException("Source and status must be informed.");
        }
        var topic = findTopicBySourceAndStatus(event);
        logCurrentSaga(event, topic);
        return topic;
    }

    private ETopics findTopicBySourceAndStatus(Event event) {
        return (ETopics) (Arrays.stream(SAGA_HANDLER)
            .filter(row -&amp;gt; isEventSourceAndStatusValid(event, row))
            .map(i -&amp;gt; i[TOPIC_INDEX])
            .findFirst()
            .orElseThrow(() -&amp;gt; new ValidationException("Topic not found!")));
    }

    private boolean isEventSourceAndStatusValid(Event event,
                                                Object[] row) {
        var source = row[EVENT_SOURCE_INDEX];
        var status = row[SAGA_STATUS_INDEX];
        return source.equals(event.getSource()) &amp;amp;&amp;amp; status.equals(event.getStatus());
    }

    private void logCurrentSaga(Event event, ETopics topic) {
        var sagaId = createSagaId(event);
        var source = event.getSource();
        switch (event.getStatus()) {
            case SUCCESS -&amp;gt; log.info("### CURRENT SAGA: {} | SUCCESS | NEXT TOPIC {} | {}",
                source, topic, sagaId);
            case ROLLBACK_PENDING -&amp;gt; log.info("### CURRENT SAGA: {} | SENDING TO ROLLBACK CURRENT SERVICE | NEXT TOPIC {} | {}",
                source, topic, sagaId);
            case FAIL -&amp;gt; log.info("### CURRENT SAGA: {} | SENDING TO ROLLBACK PREVIOUS SERVICE | NEXT TOPIC {} | {}",
                source, topic, sagaId);
        }
    }

    private String createSagaId(Event event) {
        return format(SAGA_LOG_ID,
            event.getPayload().getId(), event.getTransactionId(), event.getId());
    }
}

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

&lt;/div&gt;



&lt;p&gt;O codigo dessa aplicação ficara assim.&lt;br&gt;
&lt;a href="https://github.com/2020nani/saga_pattern/tree/master/orchestrator" rel="noopener noreferrer"&gt;API Saga Pattern - Orchestrator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/2020nani/saga-pattern-in-microservices-parte-4-g82"&gt;Parte 4&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/nanialmeida/" rel="noopener noreferrer"&gt;linkedin&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/2020nani" rel="noopener noreferrer"&gt;github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kafka</category>
      <category>java</category>
      <category>eventdriven</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Saga Pattern in Microservices - Parte 4</title>
      <dc:creator>Hernani Almeida</dc:creator>
      <pubDate>Tue, 12 Mar 2024 02:09:56 +0000</pubDate>
      <link>https://dev.to/2020nani/saga-pattern-in-microservices-parte-4-g82</link>
      <guid>https://dev.to/2020nani/saga-pattern-in-microservices-parte-4-g82</guid>
      <description>&lt;p&gt;Ferramentas necessárias:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.oracle.com/java/technologies/downloads/" rel="noopener noreferrer"&gt;Java&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/desktop/windows/install/#:~:text=%20Install%20Docker%20Desktop%20on%20Windows%20%F0%9F%94%97%20,to%20authorize%20the%20installer%20and%20proceed...%20More%20" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;IDE de sua preferencia&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/2020nani/saga-pattern-in-microservices-parte-2-122e"&gt;Configuração do ambiente conforme a parte 2 do artigo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vamos criar três aplicações com os nomes de &lt;strong&gt;Adress-Service(Java)&lt;/strong&gt;, &lt;strong&gt;UserRegistration&lt;/strong&gt; e &lt;strong&gt;Validated-Document-Service(Kotlin)&lt;/strong&gt; no &lt;a href="https://start.spring.io/" rel="noopener noreferrer"&gt;spring starter&lt;/a&gt; com as seguintes dependências necessárias&lt;/p&gt;

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

&lt;p&gt;Essas apis receberam o payload via tópico kafka conforme listener do kafka configurado nelas e integrarão com outro service nosso construído em Nodejs/Graph que nos retornara os dados que precisamos, a &lt;strong&gt;AdressService&lt;/strong&gt; ira buscar e adicionar o endereço do usuário no payload enquanto que a &lt;strong&gt;Validated-Document-Service&lt;/strong&gt; ira validar se o documento do usuário não esta guardado dentro de uma lista de documentos bloqueados.&lt;br&gt;
Feito isso a mensagem e enviada para o topico a api &lt;strong&gt;User-Registration&lt;/strong&gt; que com o payload com os dados completo do usuário armazeno-os no banco de dados postgres.&lt;br&gt;
Abaixo deixarei o link para acessar o código das aplicações no github.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/2020nani/saga_pattern/tree/master/adress-service" rel="noopener noreferrer"&gt;API Saga Pattern - AdressService(Java)&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/2020nani/saga_pattern/tree/master/validated-document-service" rel="noopener noreferrer"&gt;API Saga Pattern - ValidatedService(Kotlin)&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/2020nani/saga_pattern/tree/master/user-registration" rel="noopener noreferrer"&gt;API Saga Pattern - UserRegistration(Kotlin)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Essas apis integrarão com outra api nossa construído em Nodejs/Graphql que nos fornecerão os dados de endereço do usuário e a lista de documentos bloqueados.&lt;br&gt;
&lt;a href="https://github.com/2020nani/saga_pattern/tree/master/data-service" rel="noopener noreferrer"&gt;API Saga Pattern - DataService(Nodejs/Graphql)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Podemos testar agora a saga para cadastrar um usuário e validar o comportamento dos microservices se integrando entre si através da orientação a eventos.&lt;br&gt;
Acesse nossa primeira api atraves do swagger por este &lt;a href="http://localhost:3000/swagger-ui/index.html" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;No endpoint /user vamos fazer a requisição inicial passando nome, cpf valido e o cep do usuario.&lt;/p&gt;

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

&lt;p&gt;Logs do fluxo da nossa saga na api orquestradora&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3u8fsyuqs0l3n0j67gbp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3u8fsyuqs0l3n0j67gbp.png" alt="Image description" width="800" height="364"&gt;&lt;/a&gt;&lt;br&gt;
Vamos pegar o transactionId no payload de retorno da requisição que fizemos acima e consultar via endpoint /user/event&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb9sh29izikrysycm07so.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb9sh29izikrysycm07so.png" alt="Image description" width="800" height="379"&gt;&lt;/a&gt;&lt;br&gt;
Isso nos retornara todo o processo que aconteceu na nossa transação com sucesso.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "id": "65efb539e7a8223c9344944f",
  "userId": "65efb538e7a8223c9344944e",
  "transactionId": "1710208312995_b931560b-58d2-4d8a-8351-3abdcf2e7268",
  "payload": {
    "id": "65efb538e7a8223c9344944e",
    "transactionId": "1710208312995_b931560b-58d2-4d8a-8351-3abdcf2e7268",
    "name": "Teste",
    "document": "91549825020",
    "cep": "18608-456",
    "createdAt": "2024-03-12T01:51:52.996"
  },
  "source": "ORCHESTRATOR",
  "status": "SUCCESS",
  "eventHistory": [
    {
      "source": "ORCHESTRATOR",
      "status": "SUCCESS",
      "message": "Saga started!",
      "createdAt": "2024-03-11T22:51:53.032"
    },
    {
      "source": "ADRESS_VALIDATION_SERVICE",
      "status": "SUCCESS",
      "message": "adress was validated successfully! {}",
      "createdAt": "2024-03-11T22:51:53.188"
    },
    {
      "source": "VALIDATED_SERVICE",
      "status": "SUCCESS",
      "message": "Document was validated successfully! {}",
      "createdAt": "2024-03-11T22:51:53.287"
    },
    {
      "source": "REGISTRATION_SERVICE",
      "status": "SUCCESS",
      "message": "user persisted with successfully! {}",
      "createdAt": "2024-03-11T22:51:54.476"
    },
    {
      "source": "ORCHESTRATOR",
      "status": "SUCCESS",
      "message": "Saga finished successfully!",
      "createdAt": "2024-03-11T22:51:54.741"
    }
  ],
  "createdAt": "2024-03-12T01:51:54.999"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos repetir esse processo porem passando um cpf que contem na lista de documentos bloqueados&lt;/p&gt;

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

&lt;p&gt;Veja pelos logs da nossa api orquestradora que ocorreu um erro na api de validated-document e que a partir dai foi enviada, via kafka, uma mensagem de rollback para api validated-service e adress-service para que ambas apaguem o que já haviam feito nessa transação&lt;/p&gt;

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

&lt;p&gt;Vamos pegar o transactionId no payload de retorno da requisição que fizemos acima e consultar via endpoint /user/event o retorno dessa saga.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "id": "65efb708e7a8223c93449451",
  "userId": "65efb708e7a8223c93449450",
  "transactionId": "1710208776483_c53613c4-4779-4402-9702-77f9e376c2a5",
  "payload": {
    "id": "65efb708e7a8223c93449450",
    "transactionId": "1710208776483_c53613c4-4779-4402-9702-77f9e376c2a5",
    "name": "Teste",
    "document": "86060970044",
    "cep": "18608-490",
    "createdAt": "2024-03-12T01:59:36.483"
  },
  "source": "ORCHESTRATOR",
  "status": "FAIL",
  "eventHistory": [
    {
      "source": "ORCHESTRATOR",
      "status": "SUCCESS",
      "message": "Saga started!",
      "createdAt": "2024-03-11T22:59:36.507"
    },
    {
      "source": "ADRESS_VALIDATION_SERVICE",
      "status": "SUCCESS",
      "message": "adress was validated successfully! {}",
      "createdAt": "2024-03-11T22:59:36.579"
    },
    {
      "source": "VALIDATED_SERVICE",
      "status": "ROLLBACK_PENDING",
      "message": "Fail to validate adress: Document {} has some pendency in our base",
      "createdAt": "2024-03-11T22:59:36.635"
    },
    {
      "source": "VALIDATED_SERVICE",
      "status": "FAIL",
      "message": "Rollback executed on validated-document validation!",
      "createdAt": "2024-03-11T22:59:36.733"
    },
    {
      "source": "ADRESS_VALIDATION_SERVICE",
      "status": "FAIL",
      "message": "Rollback executed on adress validation!",
      "createdAt": "2024-03-11T22:59:36.876"
    },
    {
      "source": "ORCHESTRATOR",
      "status": "FAIL",
      "message": "Saga finished with errors!",
      "createdAt": "2024-03-11T22:59:36.933"
    }
  ],
  "createdAt": "2024-03-12T01:59:36.955"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vlw pessoal por visualizarem mais esse artigo e deixo aqui minhas redes sociais para quem quiser me adicionar e trocar uma ideia sobre desenvolvimento de softwares para aprendermos juntos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/nanialmeida/" rel="noopener noreferrer"&gt;linkedin&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/2020nani" rel="noopener noreferrer"&gt;github&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>graphql</category>
      <category>postgres</category>
      <category>node</category>
    </item>
    <item>
      <title>Desacoplando frontend com module-federation Angular - Parte 2</title>
      <dc:creator>Hernani Almeida</dc:creator>
      <pubDate>Sat, 03 Jun 2023 13:29:40 +0000</pubDate>
      <link>https://dev.to/2020nani/desacoplando-frontend-com-module-federation-angular-parte-2-4le1</link>
      <guid>https://dev.to/2020nani/desacoplando-frontend-com-module-federation-angular-parte-2-4le1</guid>
      <description>&lt;p&gt;Ferramentas necessárias:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://angular.io/cli" rel="noopener noreferrer"&gt;Angular cli&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.visualstudio.com/download" rel="noopener noreferrer"&gt;VSCode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/2020nani/desacoplando-frontend-com-module-federation-angular-parte-1-5enm"&gt;Artigo Parte 1&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vamos continuar a implementação da nossa aplicação, abra o terminal na pasta &lt;code&gt;mfe-1&lt;/code&gt; e rode o seguinte comando para instalar a lib do module-federation e configurar o webpack da aplicação.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng add @angular-architects/module-federation --project mfe-1 --port 4201 --type remote --skip-confirmation 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Logo apos digite code . para abrir o vscode e vermos o codigo de nossa aplicação.&lt;/p&gt;

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

&lt;p&gt;Mude os seguintes arquivos dentro do código.&lt;br&gt;
&lt;code&gt;app.component.html&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;&amp;lt;h1&amp;gt;Aqui e o Mfe-1&amp;lt;/h1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;app.module.ts&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;import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { CommonModule } from '@angular/common';
import { AppRoutingModule } from './app-routing.module';

@NgModule({
  declarations: [AppComponent],
  imports: [CommonModule, AppRoutingModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Detalhe que veja que passamos no import desse module o &lt;strong&gt;CommomModule&lt;/strong&gt; pois esse module da aplicação e um module filho da nossa aplicação host.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app-routing.module.ts&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;import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AppComponent } from './app.component';

const MFE1_ROUTES: Routes = [
  {
    path: '',
    component: AppComponent,
  },
];

@NgModule({
  imports: [RouterModule.forChild(MFE1_ROUTES)],
  exports: [RouterModule],
})
export class AppRoutingModule {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Outro detalhe aqui tambem, passamos no nosso RouterModule como &lt;strong&gt;RouterModule.forChild&lt;/strong&gt; pois essa rota será filha da rota root da nossa aplicação host.&lt;br&gt;
&lt;code&gt;webpack.config.js&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;const {
  shareAll,
  withModuleFederationPlugin,
} = require("@angular-architects/module-federation/webpack");

module.exports = withModuleFederationPlugin({
  name: "mfe-1",

  exposes: {
    "./Module": "./src/app/app.module.ts",
  },

  shared: {
    ...shareAll({
      singleton: true,
      strictVersion: true,
      requiredVersion: "auto",
 },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feito isso digite o seguinte comando no terminal para rodar a aplicação &lt;code&gt;npm run start&lt;/code&gt; e acesse nosso host e clique no link &lt;code&gt;Acesse Mfe-1&lt;/code&gt; e podemos ver nosso mfe sendo acessado via host.&lt;/p&gt;

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

&lt;p&gt;Siga os mesmos passos dentro da pasta onde foi criado o projeto mfe-2, porem para instalar a lib do module-federation e configurar o webpack digite o seguinte comando no terminal.&lt;br&gt;
&lt;code&gt;ng add @angular-architects/module-federation --project mfe-2 --port 4202 --type remote --skip-confirmation&lt;/code&gt;&lt;br&gt;
Após isso ajuste os seguintes arquivos para ficar assim.&lt;br&gt;
Mude os seguintes arquivos dentro do código.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app.component.html&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;&amp;lt;h1&amp;gt;Aqui e o Mfe-2&amp;lt;/h1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;app.module.ts&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;import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { CommonModule } from '@angular/common';
import { AppRoutingModule } from './app-routing.module';

@NgModule({
  declarations: [AppComponent],
  imports: [CommonModule, AppRoutingModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Detalhe que veja que passamos no import desse module o &lt;strong&gt;CommomModule&lt;/strong&gt; pois esse module da aplicação e um module filho da nossa aplicação host.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;app-routing.module.ts&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;import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AppComponent } from './app.component';

const MFE2_ROUTES: Routes = [
  {
    path: '',
    component: AppComponent,
  },
];

@NgModule({
  imports: [RouterModule.forChild(MFE2_ROUTES)],
  exports: [RouterModule],
})
export class AppRoutingModule {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Outro detalhe aqui tambem, passamos no nosso RouterModule como &lt;strong&gt;RouterModule.forChild&lt;/strong&gt; pois essa rota será filha da rota root da nossa aplicação host.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;webpack.config.js&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;const {
  shareAll,
  withModuleFederationPlugin,
} = require("@angular-architects/module-federation/webpack");

module.exports = withModuleFederationPlugin({
  name: "mfe-2",

  exposes: {
    "./Module": "./src/app/app.module.ts",
  },

  shared: {
    ...shareAll({
      singleton: true,
      strictVersion: true,
      requiredVersion: "auto",
 },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feito isso digite o seguinte comando no terminal para rodar a aplicação &lt;code&gt;npm run start&lt;/code&gt; e acesse nosso host e clique no link &lt;code&gt;Acesse Mfe-2&lt;/code&gt; e podemos ver nosso mfe sendo acessado via host.&lt;/p&gt;

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

&lt;p&gt;Podemos agora a cada clique no link acessar remotamente nossas aplicações &lt;code&gt;mfe-1&lt;/code&gt; e &lt;code&gt;mfe-2&lt;/code&gt; o que nos possibilita, por exemplo fazer alterações e subir um deploy na aplicação mfe-1 sem que isso interfira na aplicação mfe-2 pois e um outro codigo totalmente independente.&lt;/p&gt;

&lt;p&gt;E isso ai devs mas um conhecimento passado, deixarei no meu &lt;a href="https://github.com/2020nani/mfe-article" rel="noopener noreferrer"&gt;github&lt;/a&gt; para quem quiser acessar o projeto&lt;br&gt;
Deixo aqui também meu &lt;a href="https://www.linkedin.com/in/nanialmeida/" rel="noopener noreferrer"&gt;linkedin&lt;/a&gt; e &lt;a href="https://www.instagram.com/her_almeida40/" rel="noopener noreferrer"&gt;instagram&lt;/a&gt; para quem quiser me adicionar, grato a todos que leram este artigo e bora aprender galera.&lt;br&gt;
*Observação: * Como um plus numa terceira parte irei me desafiar a construir um componente angular utilizando module-federation para servir como lib de algum componente para se usar nas aplicações, exemplo um botão padrão para usar em todas as aplicações, e compartilho aqui numa terceira parte.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>modulefederation</category>
      <category>javascript</category>
      <category>microfrontend</category>
    </item>
  </channel>
</rss>
