Passo a passo de como criar seu Pokedex com Spring WebFlux
Tags: java, heroku, spring, mongodb
Published: 2020-04-21 22:33:18

Oláaa neste artigo você irá aprender a criar uma aplicação de Create, Read, Update e Delete usando Spring Webflux, com os dados salvos num banco MongoDB e por fim hospedado no Heroku!

Repositório do projeto criado: https://bit.ly/pokedex-reativo

Ao final deste tutorial, você terá seu próprio pokedex, e poderá atualizar, deletar e criar seus pokémons no seu próprio repositório, com conceitos de reatividade usando **Events Streams**, e **Endpoints Funcionais** de forma simples e usual, um projeto bem bacana pra ter como portfólio!
**Curtiu? Então vamos lá... (ɔ◔‿◔)ɔ**

#Setting up the project
O que você precisa ter instalado antes de começar:
* JDK 8 ou 9 
* Uma IDE para o desenvolvimento, eu vou usar o [IntelliJ](https://www.jetbrains.com/idea/download/#section=windows)
* O [Heroku CLI](https://id.heroku.com/login)
* Possuir o Maven 3 com suas variáveis de ambiente configuradas
* Postman

> É muito importante que você tenha o Maven 3, pois o Heroku CLI só roda nessa versão... Caso você não o tenha [Clique aqui](https://maven.apache.org/download.cgi) e instale o maven na versão correta para fazer sua aplicação subir corretamente ;)

Agora você deve acessar o site [Spring Initialzr](https://start.spring.io/) , e selecionar as seguintes dependências:
* Spring Reactive Web
* Spring Data Reactive MongoDB 
* Embedded MongoDB Database

No Group usaremos: ` com.pokedex `
No Artifact: ` reactiveweb `

O package name é gerado automaticamente!

Depois de gerado todas as variáveis seu Spring Initializr deve ficar assim:
![tela do spring initializier com todas as configurações que o usuário escolheu de acordo com o tutorial](https://dev-to-uploads.s3.amazonaws.com/i/ndiw8uy9vvfeceul7fjv.PNG)

Prontinho, agora é só clicar em ` GENERATE CRTL+ `,   e o spring initializr irá gerar um arquivo em ZIP e você deve extrair esse arquivo num **diretório que você consiga localizar depois**.

# Importando o projeto
Depois de extraído o arquivo você deve abrir sua IDE, no caso vou abrir o IntelliJ e cliar em **import project**

![imagem do intellij idea logo que abrimos](https://dev-to-uploads.s3.amazonaws.com/i/g3tk1n0gcb6vn5d3dh9j.PNG)

Clicando em **import project** você verá todos seus diretórios, basta localizar onde estar o projeto que você baixou do Spring Initialzr, e importá-lo clicando em **ok**
![imagem dos diretórios no windows](https://dev-to-uploads.s3.amazonaws.com/i/hlfcsqsqcln22dtmgsor.PNG)

Irá aparecer uma janela com duas opções, você deverá escolher: **Maven**, pois nosso projeto será importando através de um modelo que já existe
![escolhendo maven como projeto base](https://dev-to-uploads.s3.amazonaws.com/i/cxkoq6fhda1a8ikc5626.PNG)
Agora você pode clicar em **finish** e será carregado todo seu projeto com as variáveis de ambiente! :p

#Configurando o pom.xml
Para nossa aplicação subir corretamente, precisamos colocar na ordem correta a dependência do mongo embbeded, ele deve ficar antes do `` <dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-webflux</artifactId>
		</dependency> ``, seu pom.xml ficará da seguinte forma:

![pom.xml](https://dev-to-uploads.s3.amazonaws.com/i/fp0i98m5sq2t66n9ui2b.PNG)
basta exlcuir o ` <scope>test</scope> ` e colocar a dependency do mongo embeded logo em seguida.

Isso fará com que nossa aplicação suba na ordem correta, se essa dependency estiver depois igual estava, nossa aplicação não iria subir no servidor, pois a mesma não iria encontrar, sua depedendy deverá ficar da seguinte forma:
             `` <dependency>
			<groupId>de.flapdoodle.embed</groupId>
			<artifactId>de.flapdoodle.embed.mongo</artifactId>
		</dependency> ``


#Subindo pela primeira vez a aplicação
Vamos ver se nossa aplicação está subindo, no canal do youtube da womakerscode temos um vídeo onde explicamos sobre o servidor Netty, caso tenha alguma dúvida só dar uma [passadinha por lá](https://www.youtube.com/watch?v=KLsM_LRYzoM&t=859s).
Subindo a aplicação iremos ver nosso servidor em ação na porta 8080.

Vou colocar um "hello world womakerscode" padrão na classe main()

Você verá que que no console nosso ` System.out.println ` irá mostrar a mensagem, e também será sinalizado a porta que nossa aplicação está
![console da aplicação](https://dev-to-uploads.s3.amazonaws.com/i/1qjrvny5nhr7tsdw9v9d.PNG)


#Criando um Model
Para realizarmos os testes no banco de dados precisamos que nossa aplicação tenha os dados para serem salvos, e também para que os métodos do MongoDB sejam encontrados. Nele ficará salvos nossas variáveis.

Para criar o package clique com o botão direito em **com.pokedex.reactiveweb** > New > Package > com.pokedex.reactiveweb.**model** > enter
![package model sendo gerado no intellij](https://dev-to-uploads.s3.amazonaws.com/i/jkdc918yk00v2h8ij2a0.PNG)

Dentro dele crie uma nova classe com o nome **Pokemon** , dentro dessa classe será colocado as informações que os pokemons terão, tais como Id, Nome, Poder etc... Dentro dessa classe coloque:

{% gist https://gist.github.com/anabneri/c83938df9817c10a1c6539f303cc09e6 %}

Agora só precisa gerar os **getter e setters** , **boolean equals** , **hashcode** , e o **toString** , você pode fazer tudo isso apertando `` ALT + INSERT `` > getter/ setter > equals() hashcode() > toString() > Override Methods > Constructor

Pode ir fazendo um seguido do outro, o IntelliJ ou IDE que você estiver utilizando irá gerar todos esses métodos pra você!

#Criando um repository
No repository é onde fica a persistência dos dados, para criá-lo clique com o botão direito em **com.pokedex.reactiveweb** > New > Package > com.pokedex.reactiveweb.**repository** > enter

Dentro desse package será criado uma **interface** com o nome de **PokemonRepository**

> Interface é uma tipo de abstração que usamos para especificar o tipo de comportamento que as classes devem implementar

Dentro nessa interface coloque o seguinte código:

{% gist https://gist.github.com/anabneri/8c5448216d6ba31b84ba7ae1ccdcab77 %}

O Spring Data já facilita muito nossa vida, sendo assim, a única coisa que precisamos colocar nessa interface é uma especificação que ela irá funcionar com o objeto Pokemon String.

> Se você clicar no **ReactiveMongoRepository** irá ver o que o ele tras por debaixo dos panos, tais como métodos mono e flux, findByID, finalAll etc..

Agora sim podemos Inicializar nosso banco de dados (͠≖ ʖ͠≖)👌

#Inicializando o MongoDB
Estamos usando o Mongo Embeded, sendo assim, não é necessário que você crie um conta ou etc, esta tudo local na nossa máquina.

Na classe Main() criaremos uma chamada do nosso banco de dados, usando o CommandLiner que é uma interface funcional que recebe variável de argumentos em cadeia.. o mesmo deve estar anotado com o **@Bean** para o spring boot entender que aquilo deve ser processado, enfim, o resultado deve ser o seguinte código:

{% gist https://gist.github.com/anabneri/8826da944458a9c340638a8cf7421cf6 %}


Aqui vemos algo de diferente, nao estamos trazendo os métodos padrões (findAll, findById etc) por que estamos trabalhando com um banco de dados embutido, mas caso você queira usar um Mongo Atlas por exemplo, o **ReactiveMongoOperations** gera essa série de métodos pra você.

Nesse código o .flatMap consulta o findAll e imprime os dados, e o thenMany faz isso também só que de forma assíncrona, e o subscribe imprime na tela também

Agora se a executarmos veremos que o banco de dados subiu, e os dados inseridos serão mostrados na tela, você terá algo assim:
![console mostrando os dados que foram salvos](https://dev-to-uploads.s3.amazonaws.com/i/eu4bjclvbbhtbl62e6mm.PNG)

#Criando o Controller
Controller é nossa classe de controller, nela estarão nossos métodos de criação, update, delete e leitura dos nossos pokémons.

Para criá-lo clique com o botão direito em **com.pokedex.reactiveweb** > New > Package > com.pokedex.reactiveweb.**controller** > enter
E repetir esse mesmo processo para criar uma classe 

Agora bora criar os métodos que já estamos chegando no resultado final  (•◡•) /

###Buscando todos os pokemons
Agora você deve criar uma instância e dentro dela terá o método para trazer todos os pokémons, ficará assim:

{% gist https://gist.github.com/anabneri/d90b062063bdc1c96d3016f5c4cca178 %}


##Bucando o Pokémon por id
Para buscar por id, colocaque o método dentro da instância, igual o anterior:

{% gist https://gist.github.com/anabneri/3a35c72db999d52744ea6365d98ef6bd %}


Você que nesse método está o **Mono** tipo pokémon? Isso significa que queremos apenas que 1 id seja chamado, e quando esse id não for encontrado, trazemos uma reposta HTTP.

O defaultIfEmpty é usado para quando o Id é chamado numa entidade vazia, ele retornará um status *NOTFOUND*

> Lembre-se de que o .map() deve retornar uma função síncrona e o resultado será capturado em um editor Mono, pois findById retorna um Mono

##Criando e salvando um novo Pokémon
Para criar um novo e salvar pokémon basta digitar o código abaixo

{% gist https://gist.github.com/anabneri/05e4f7b12a6adaa1d993453ee8cb2f61 %}

Retornará um Mono<Pokemon> por que é o que será retornado no repositório.

##Atualizando um Pokémon
Agora vamos combinar tudo o que você já viu até aqui para atualizar um Pokémon. Para atualizarmos um pokémon receberemos um id, e uma instância do pokémon com novos valores a serem atualizados.

Vamos começar procurando por id, e se ele for encontrado será atualizado ao contrário será recebido um status *NOTFOUND*

{% gist https://gist.github.com/anabneri/dbf60d0ea888310c1a8be0b613ca8915 %}

A segunda parte do código um operador map para essa transformação, e assim se um Mono vazio for retornado com defaultEmpty ele retornará um status NOTOFUND, esse bloco de código poderia também ser feito com if/ else, mas o jeito que fizemos foi do modo **declarativo**

##Excluindo um Pokémon
O método para exlcuir é semelhante aos anteriores também, para deletar quando criar um método que deleta um pokémon por id:

{% gist https://gist.github.com/anabneri/c423a3625cce6a8daceefaa0afca927d %}

E outro método para deletar TODOS os Pokémons

{% gist https://gist.github.com/anabneri/b771973616d4b648e6e91eefa5866693 %}

Prontinho, agora temos nosso CRUD completo onde criamos de maneira reativa e funcional, agora precisamos criar nosso Event Stream (parte mais legal o/)

##Criando um Event Stream ᕙ(`▿´)ᕗ
Para criarmos nosso método de eventos no controller, precisamos criar a classe onde estão os atributos do evento, para isso dentro do package **model** crie uma classe **PokemonEvent** , com os seguinte código:

````java
public class PokemonEvent {
    private Long eventId;
    private String eventType;
}

````

Da mesma forma que foi feito com o classe Pokémon dentro do package Model logo acima,  só vai precisa gerar os **getter e setters** , **boolean equals** , **hashcode** , e o **toString** , você pode fazer tudo isso apertando `` ALT + INSERT `` > getter/ setter > equals() hashcode() > toString() > Override Methods > Constructor

showww, agora vamos voltar na classe **PokemonController** , e criar nosso método de eventos, que ficará da seguinte forma:

````java
 @GetMapping(value = "/events", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<PokemonEvent> getPokemonEvents() {
        return Flux.interval(Duration.ofSeconds(5))
                .map(val ->
                        new PokemonEvent(val, "Product Event")
                );
    }

````


O interval traz o tanto de segundos que o meu evento será mostrado, nesse caso de 5 em 5 segundos um evento novo é gerado!

Estamos quase acabando, agora só falta testar nossos endpoints ( ͡~ ͜ʖ ͡°)

#Testando a aplicação
Para testar nossa aplicação vamos ver se tudo irá subir certinho, para isso vá até o método main() e starte ele, e fique de olho no console para ver se não surge nenhum erro, a resposta deve voltar mais ou menos assim:
![mensagem de êxito no console](https://dev-to-uploads.s3.amazonaws.com/i/pchxhipfx0r8ysnpcwmg.PNG)

Agora bora pro postman testar os endpoints

####Buscando todos os Pokémons
O primeiro método que vamos testar é o GET, que vai trazer todos os pokémons que foram salvos, no postman ira trazer os seguintes resultados:
![resultado da busca GET dos pokemons](https://dev-to-uploads.s3.amazonaws.com/i/4v0o32uw42i08w3wplgy.PNG)

Veja que na busca optamos por GET, pois estamos "pegando" todos os pokémons, para testar os demais como: "PUT", "POST" ... etc, basta mudarmos essa opção, então bora lá

####Buscando um Pokémon por id
Para buscar por id, basta copiar e colar um id que foi gerado na resposta do GET
![buscando um pokémon por id ](https://dev-to-uploads.s3.amazonaws.com/i/ia05dzrg0j10mmwdd8ba.PNG)

####Inserindo um novo Pokémon
No próprio postamn mude a requisição para **POST** e no **Body** selecione **raw**  > **JSON** pois queremos salvar em formato json, e digite:

````java
   {
        "nome": "IbySaur",
        "categoria": "Semente",
        "habilidades": "OverGrow",
        "peso": 13.0
    }

````

Após isso, clique em **SEND** e seu pokémon será salvo!
Deverá retornar um *STATUS 201** o que mostra que foi criado com êxito, para ter certeza, vamos voltar no **GET** , copiar e colar o id gerado, que ele mostrará nosso pokémon criado..

> O id não precisa colocar pois ele é gerado automaticamente pelo MongoDB

####Deletando um Pokémon
Agora vamos deletar os métodos **deleteALL** e **deleted**, sendo assim no postman vamos mudar a requisição para **DELETE**

![deletando um pokémon no postman](https://dev-to-uploads.s3.amazonaws.com/i/6qwnx8ppazwilsjasuj3.PNG)

Vejam que eu coloco o id de algum pokémon que eu queira excluir

Se eu tirar esse id ele vai exlcuir TODOS OS POKÉMONS

#Testando o Events Stream 
Vimos que nosso CRUD está no esquema já, ou seja, está funcionando bem lindão...
Com nossa aplicação iniciada ainda, vamos testar o events stream, para isso vá até um browser se sua preferência e digite: 

` http://localhost:8080/pokemons/events `

 E você vai ver a mágica acontecer a cada 5 segundo estará no retornando um evento de pokémons

![resposta do browser na consulta de pokemons](https://dev-to-uploads.s3.amazonaws.com/i/42h661k4qpym00rm0kk2.PNG)

Se você abrir essa mesma requisição em outra janela, você vai ver que no events stream vai permitir que outra requisição seja chamada sem esperar que a anterior termine, isso é uma chama não-bloqueando, típica do Spring Webflux.

#Deploy no Heroku
Shoooow agora você já tem uma aplicação topzera, bora subir ela na nuvem?

Para subir nossa aplicação, precisamos colocar o plugin do heroku no nosso pom.xml:

````xml
<project>
  ...
  <build>
    ...
    <plugins>
      <plugin>
        <groupId>com.heroku.sdk</groupId>
        <artifactId>heroku-maven-plugin</artifactId>
        <version>3.0.2</version>
      </plugin>
    </plugins>
  </build>
</project>

````


Agora vá até a pasta da sua aplicação, usando um terminal (eu vou usar o gitbash) ,  e digite ` heroku login ` , para acessar sua conta no heroku

Irá aparecer uma janela assim pra você:
![login heroku](https://dev-to-uploads.s3.amazonaws.com/i/ij5bdqyb3r1sd02vg3en.PNG)

Clique em Login e já pode fechar essa janela que você estará com o login ativo no Heroku!

Agora é só esperar o terminal processar
![terminal processando o login no heroku](https://dev-to-uploads.s3.amazonaws.com/i/h7ezz4egnh36jaubrl2l.PNG)

Depois que terminar de carregar, iremos criar um app para hospedar nossa aplicação, faremos isso com o comando ` heroku create `

E estamos quase lá, seu app foi criado, no terminal ele vai te gerar um link e essa mensagem:
![mensagem de que o app foi criado com sucesso](https://dev-to-uploads.s3.amazonaws.com/i/3w71sxu8r6uh0j5nxfmy.PNG)

Estamos prontos pro Deploy

Se seu aplicativo é um standalone (e, portanto, requer um tipo de processo), você pode implantar com este comando: ` mvn clean heroku:deploy `
Só esperar um segundinhos e verificar os logs...

Se a mensagem **BUILD SUCESS** aparecer significa que tudo deu certo, pode respirar de alívio!
![build feito com sucesso](https://dev-to-uploads.s3.amazonaws.com/i/fivu3kw2zycex79vbr40.PNG)

 PARABÉNSSS sua aplicação subiuuu
![Will Smith dançando](https://media.giphy.com/media/b5LTssxCLpvVe/giphy.gif)

Para acessar basta digitar ` heroku open `
![dashboard do heroku](https://dev-to-uploads.s3.amazonaws.com/i/1irez40cysf3jdr1dmrq.PNG)

#Conclusão
Spring Webflux é um módulo muito bacana no SpringBoot, com ele além de criamos um CRUD podemos criar uma sequência de eventos, mas isso não quer dizer que sempre devemos usar aplicações reativas, tudo depende do seu cenário e da viabilidade

...

E se você chegou até aqui parabéns você é um **vencedor**, acredito que não existe nada mais recopensador do que ver a nossa aplicação funcionando né? Então compartilhe também, e coloque no github para que mais e mais pessoas possam aprender assim como você! ʕ•́ᴥ•̀ʔっ

O código desta aplicação está no meu Github -> 
https://bit.ly/pokedex-reativo
Dê uma estrelinha lá no github se te ajudou <3


Referências:
[Heroku DevCenter](https://devcenter.heroku.com/articles/deploying-java-applications-with-the-heroku-maven-plugin)
[Canal do Youtube da Michelli Brito](https://www.youtube.com/channel/UC2WbG8UgpPaLcFSNJYwtPow)

Nos vemos na próxima, dêem likesss e compartilhem, e vejam os outros artigos da womakerscode quem quiser me seguir nas redes socias @anabneri #tamojunto