Desafio Orange Talents

 

Desafio: Orange Talents 

Pedro Henrique Gonçalves Barcelos

Resumo

O desenvolvimento de API's, em suas diversas formas, evoluiu bastante nas ultimas décadas e,
nesse sentido, se tornou uma proficiência vital para os jovens developers. Empresas referências no mercado, como a Zup, já introduziram conhecimentos como a Spring Framework em seus requisitos nos "programas de estágio", como por exemplo o Orange Talents. Essa atitude, indiretamente, desperta nos jovens a vontade cada vez mais cedo entrar em contato com essas tecnologias, o que promove uma maior especialização da mão de obra, semeando melhores frutos na vida desses amantes por tecnologia.

Minha história

Eu me chamo Pedro, tenho dezoito anos, nasci e resido em Belo Horizonte, MG. Desde criança apaixonado por tecnologia, ingressei no curso de Ciência da Computação na PUC-MG, em fevereiro de 2020. O curso vem sido bem desafiador, mas ao mesmo tempo satisfatório, a cada semestre tenho mais certeza do que quero.

Em Janeiro de 2021 conheci um amigo, que me apresentou a Zupe, posteriormente, o Orange TalentsMe inscrevi e logo comecei os estudos, pois nunca havia entrado em contato com Spring Frameworkafinal essa tecnologia ainda não é ensinada nas universidades, infelizmente.

Estou fazendo um curso para me especializar em Spring e suas dependências. É um prazer fazer parte desse desafio. Independente do resultado, sinto muito orgulho do que já foi feito. É um prazer! 

Clique aqui para ser redirecionado para o meu post no meu blog!

Vamos ao desafio!!!

Tecnologias usadas

    1. Spring Boot

Spring Boot faz parte do conjunto Spring Framework e é muito bem visto pela comunidade como um otimizador de produção de códigos. Perfeito para a criação de aplicações, o Spring boot reduz drasticamente o tempo antes gasto para configurar uma aplicação, antes mesmo de inicia-la. Além disso, o Spring Boot possuí servidores HTTP embutidos, como é o caso do Tomcat, possibilitando o teste de páginas web, como o nosso caso! Viva o Spring Boot!

A seguir, veremos como é fácil configurar o arquivo "pom.xml", injetando as dependencias necessárias para a aplicação (trecho autoral do código):

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>io.github.pedrobarcelos</groupId>
<artifactId>OrangeTalents</artifactId>
<version>1.0-SNAPSHOT</version>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
</parent>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>
 

    2. Maven


Apache Maven, mais conhecido por "Maven", é uma ferramenta essencial de gerenciamento e automação de construção (build) de projetos. O Maven, por si só, fornece muitas funcionalidades, por meio de "plugins". Ademais, ele emprega boas práticas de organização, desenvolvimento e manutenção de projetos.

No trecho a seguir, vemos um puglin do maven injetado no arquivo "pom.xml" (trecho autoral do código):

    <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

    3. Intellij IDEA



O Intellij IDEA, ou simplesmente "Intellij", é uma poderosa IDE (integrated development environment) desenvolvido pela JetBrains. O Intellij apresenta funcionalidades únicas, a tornando um dos "preferidinhos" dos devs.  Auto Complete, Quick Search e Search Pattern são algumas das vantagens dessa IDE, que por sinal foram muito usadas por mim nesse projeto.

No gif a seguir, vemos em prática o Intellij, fornecendo ao usuário Getters e Setters automáticos para qualquer método (trecho autoral do código).



    4. JPA + H2 Database Engine + Hibernate

H2 é um banco de dados que opera em memória, isto é, a cada "run" ele será inicializado do zero. Isso não impede o developer de popular o banco com as mesmas entidades e atributos a cada vez que ele é inicializado. Isso é possível de varias formas, uma delas é injetando comandos SQL em um arquivo "data.sql". O H2 é muito usado em projetos Spring pela sua facilidade de configuração.

Hibernate é uma framework de persistência de dados, muito utilizado para a linguagem java. Tal framework se mostra ótima para realizar mapeamento objeto-relacional (ORM ). 

Java Persistence API, mais conhecido pela abreviatura JPA, é uma coleção de métodos e classes que  proporcionam meios de armazenar os dados presentes nos objetos implementados no sistema desenvolvido dentro das entidades no banco de dados.

    5. Postman

O Postman é uma aplicação que, além de simples e intuitiva, permite realizar requisições HTTP, facilitando consideravelmente o teste e depuração de serviços REST. Essa aplicação se tornou muito útil no nosso projeto por permitir enviar e receber dados no formato JSON.

Abaixo vemos o cadastro do cliente " Orange Talents ", com cpf = 11111111111, e já vacinado. Essa requisição foi feita com o método POST na rota pré-definida no controller do Cliente:

Perceba que obtivemos como reposta o Status "201 Created", que indica que tudo ocorreu bem.


Agora, utilizando o método GET e passando como parâmetro a chave primária {cpf} do cliente, percebe-se que os dados foram gravados com sucesso no banco de dados!

Note que recebemos o Status "200 OK", novamente indicando sucesso na requisição HTTP


    6. GitHub 
Manter o seu GitHub em dia com os seus projetos é mais do que essencial para qualquer profissional da área de Ciência da Computação e afins. Não foi diferente nesse projeto! A plataforma de versionamento de códigos foi utilizada para manter a organização do código e fazer alguns "saves", isto é, algumas versões do projeto foram postadas no git em forma de repositório, para serem facilmente acessadas depois.

Na imagem a seguir vemos o repositório criado por mim na ultima versão do coódigo.



Como o projeto foi feito

    1. Analisar os dados, e projetar o BD 

    
Seguindo essa premissa, já podemos definir as entidades:

Cliente

Vacinas

Agora, podemos atribuir à eles, seus respectivos atributos (exemplo):

CREATE TABLE CLIENTE (
CPF INTEGER PRIMARY KEY,
EMAIL VARCHAR(100),
NASCIMENTO TIMESTAMP,
NOME VARCHAR(100),
VACINADO BIT NOT NULL
);

CREATE TABLE VACINA (
ID INTEGER PRIMARY KEY AUTO_INCREMENT,
NOME VARCHAR(100),
EMAIL_VACINADO VARCHAR(100) REFERENCES CLIENTE (EMAIL),
DATA_APLICACAO TIMESTAMP,
);

    2. Injeção de dependências e pom.xml

Para esse projeto, vamos configurar o pom.xml da seguinte maneira:
Inserir o seguinte parent:
    
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
</parent>

Em seguida, teremos que injetar as seguintes dependências:

Spring boot starter
Spring boot starter web
Spring boot data JPA
h2

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
</dependencies>

Finalmente, vamos inserir o plugin do maven ao nosso projeto spring:

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

    3. Criar as classes entidades

Precisamos criar as entidades da nossa aplicação em forma de Java Class. Um passo muito importante é ficar atento as "annotations" que devem ser acopladas a essas classes, por exemplo:

    Annotations da classe:
    @Entity - indica que esta classe é uma entidade
    @Table - indica que esta classe deve ser mapeada como uma tabela
    
    Annotations de atributos:
    @Id - mapeia esse atributo como uma PRIMARY KEY
    @Column - mapeia esse atributo como uma coluna
    @ManyToOne - mapeia esse atributo como FOREIGN KEY e indica a relação "Muitos pra um"
    @OneToMany - mapeia esse atributo e indica a relação "Um para muitos"

Abaixo, temos a entidade Cliente devidamente mapeada, e com todos os métodos set(), get() e toString():

package io.github.pedrobarcelos.domain.entity;

import javax.persistence.*;
import java.time.LocalDate;
import java.util.Set;

@Entity
@Table( name = "cliente" )
public class Cliente {

@Id
@Column(name = "cpf", length = 11)
private String cpf;

@Column(name = "email", length = 100)
private String email;

@Column(name = "nome", length = 100)
private String nome;

@OneToMany(mappedBy = "cliente", fetch = FetchType.LAZY)
private Set<Vacina> vacinas;

@Column(name = "nascimento")
private LocalDate nascimento;

@Column(name = "vacinado")
private boolean vacinado = false;

public Cliente() {
}

public String getCpf() {
return cpf;
}

public void setCpf(String cpf) {
this.cpf = cpf;
}

public String getNome() {
return nome;
}

public void setNome(String nome) {
this.nome = nome;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public LocalDate getNascimento() {
return nascimento;
}

public void setNascimento(LocalDate nascimento) {
this.nascimento = nascimento;
}

public boolean isVacinado() {
return vacinado;
}

public void setVacinado(boolean vacinado) {
this.vacinado = vacinado;
}

@Override
public String toString() {
return "Cliente{" +
"cpf='" + cpf + '\'' +
", nome='" + nome + '\'' +
", email='" + email + '\'' +
", nascimento=" + nascimento +
", vacinado=" + vacinado +
'}';
}
}

   4. Criar os repositórios das respectivas entidades

Os  repositórios em como objetivo criar beans para a parte de persistência, além de capturar exceções específicas de persistência e repeti-las novamente como uma das exceções não verificadas e unificadas do Spring. As annotations que são usadas nessa etapa são:

 

@Repository - mapeia o arquivo como um respository

@Query - permite fazer consultas e modificações no banco de dados. Lembrando sempre que, quando a requisição for fazer alguma mudança no banco, é necessário utilizar também a annotation @Modifying ( exemplo: delete )


@Query(" delete from Cliente c where c.nome =:nome ")
@Modifying
void deleteByNome(String nome);

   5. Criando os controllers, de Cliente e de Vacina

Nos controllers, iremos definir e configurar o fluxo da aplicação. Nele definimos as rotas usadas nas requisições HTTP, definimos todas as exceções possíveis, como por exemplo: um erro na requisição HTTP (BAD REQUEST), a tentativa de acessar um cliente ou vacina inexistente no banco, etc. As annotation usadas nos Controllers são:

 

@RestController - permite definir um controller com características REST

@RequestMapping - permite definir uma rota

 

@GetMapping  - indica que lidará com Requests HTTP do tipo : GET

@DeleteMapping - indica que lidará com Requests HTTP do tipo : DELETE

@PostMapping - indica que lidará com Requests HTTP do tipo : POST

@PutMapping - indica que lidará com Requests HTTP do tipo : PUT

 

@RequestBody indica que o valor do objeto virá do corpo da requisição em forma de parâmetro.

 

Abaixo temos métodos do controller de Vacina:


@PostMapping
@ResponseStatus(CREATED)
public Vacina save(@RequestBody Vacina vacina ){
return repository.save(vacina);
}

@PutMapping("{id}")
@ResponseStatus(NO_CONTENT)
public void update( @PathVariable Integer id, @RequestBody Vacina vacina ){
repository
.findById(id)
.map( p -> {
vacina.setId(p.getId());
repository.save(vacina);
return vacina;
}).orElseThrow( () ->
new ResponseStatusException(HttpStatus.NOT_FOUND,
"Vacina não encontrado."));
}

@DeleteMapping("{id}")
@ResponseStatus(NO_CONTENT)
public void delete(@PathVariable Integer id){
repository
.findById(id)
.map( p -> {
repository.delete(p);
return Void.TYPE;
}).orElseThrow( () ->
new ResponseStatusException(HttpStatus.NOT_FOUND,
"Vacina não encontrado."));
}

@GetMapping("{id}")
public Vacina getById(@PathVariable Integer id){
return repository
.findById(id)
.orElseThrow( () ->
new ResponseStatusException(HttpStatus.NOT_FOUND,
"Vacina não encontrado."));
}

    6. Testes com o Postman

Nessa etapa, iremos testar a nossa aplicação por meio do Postman. Nele, iremos inserir requisições HTTP por meio das rotas definidas nos controllers, e, se tudo der certo, obteremos as respostas esperadas.

 

Popular um banco com um cliente X apenas como seu CPF (primary key):

 

http://localhost:8080/api/clientes 

body em Jason:

    

{

    "cpf" : 98542154879

}

 

Status HTTP esperado: 201 Created 

 

Status HTTP obtido: 201 Created




Popular um banco com um cliente Pedro, que possui o CPF 98542154879, email Pedro.icloud.com e que ja foi vacinado contra covid:

 

http://localhost:8080/api/clientes 

body em Jason:

    

{

    "cpf" : 98542154879,

    "vacinado" : true,

    "nome" : "Pedro",

    "email" : "pedro.icloud.com"

}

 

Status HTTP esperado: 201 Created 

 

Status HTTP obtido: 201 Created



Com esse cliente criado, agora queremos acessá-lo por meio do método GET, passando como parâmetro o seu CPF:

 

http://localhost:8080/api/clientes/98542154879

 

Status HTTP esperado: 200 OK

 

Status HTTP obtido: 200 OK



E se tentarmos acessar esse cliente passando o CPF errado (inexistente) ?

 

http://localhost:8080/api/clientes/99999999999

 

Status HTTP esperado: 404 NOT FOUND

 

Status HTTP obtido: 404 NOT FOUND



"message" : "Cliente não encontrado"

Agora o cliente deseja alterar o seu nome para "Victor", utilizando o método PUT:


Testando se funcionou a partir do método GET:



Finalizando os testes com a entidade Cliente, vamos deletar esse cliente pelo método DELETE, passando como parâmetro seu CPF:



Agora confirmando se ele foi deletado, utilizando o método GET para procurar por um cliente com o CPF excluido:


Agora vamos fazer as mesmas requisições com a entidade Vacina:


Registrando a vacina:



Confirmando se a vacina foi registrada:


Alterando o nome da vacina:


Confirmando se o nome foi alterado:



Deletando a vacina:


Confirmando se a vacina foi deletada:


Problemas enfrentados ( e não superados )

1) Dificuldade ao manipular chaves estrangeiras ( resultou em um problema na classe Vacina, onde a variável email_vacinado não funcionava da forma esperada, e é mostrada com o nome "cliente", sempre com o valor NULL.

2) Interface WEB: O projeto apresentado não possui um front-end, muito devido ao prazo estipulado e por ser o meu primeiro contato com Spring.

3) Não foi possível concluir de fato a API, faltou migrar o Banco para um banco que não seja de memória, como o MYSQL, faltaram as classes Services e Security, alem das DTO's.





Comentários

Postagens mais visitadas