O projeto é uma aplicação de API RESTful, desenvolvida utilizando Spring Boot 3 e Java 21. Decidi trabalhar nesse projeto para aprimorar minhas habilidades em desenvolvimento de software e revisar conceitos arquiteturais REST/RESTful.
O objetivo principal do projeto é criar uma API robusta e escalável que integre-se com um banco de dados MySQL e ofereça suporte a diferentes formatos de conteúdo, como JSON, XML e YAML, através da negociação de conteúdo. Implementei também autenticação com JWT e Spring Security para garantir a segurança da API.
Um dos principais desafios durante a implementação foi lidar com o versionamento da API e garantir a compatibilidade entre as diferentes versões. Além disso, a integração com o Swagger Open API e a implementação de HATEOAS (nível 3 de maturidade REST) foram aspectos interessantes que exigiram uma compreensão mais aprofundada dos princípios RESTful.
Com esse projeto, aprendi/revisei não apenas sobre o desenvolvimento de API's RESTful com Spring Boot, mas também sobre boas práticas de desenvolvimento, como testes unitários e de integração com JUnit 5, Mockito e REST Assured. A dockerização da aplicação também foi uma experiência valiosa, permitindo uma implantação mais consistente e simplificada.
Em resumo, este projeto foi uma oportunidade de aplicar e consolidar meus conhecimentos em desenvolvimento de API's RESTful, além de proporcionar aprendizado contínuo em diversas áreas, desde conceitos arquiteturais até boas práticas de desenvolvimento e implantação de software.
- Server
- Client:
Este repositório inclui um fluxo de trabalho do GitHub Actions que representa uma integração contínua (CI). Esse fluxo de trabalho é responsável por instalar, testar e enviar os serviços do repositório em forma de contêineres Docker para o DockerHub, preparando o projeto para ser implantado.
A adição de etapas de implantação contínua (CD) dependerá das necessidades específicas do projeto e do ambiente de implantação. Por exemplo, poderíamos adicionar etapas para implantar as imagens Docker em um ambiente de produção após a conclusão bem-sucedida da construção, ou ainda utilizar serviços específicos de provedores de nuvem para gerenciar o processo de implantação. Um exemplo de implantação na AWS se encontra no arquivo aws-ci-cd.
Abaixo é possível observar as etapas realizadas, desde o desenvolvimento até o envio para o Docker Hub, conforme configurações do fluxo de trabalho.
- Desenvolvedor comita o código e faz o PUSH para o GitHub na branch main.
- O gatilho do GitHub inicia a construção no GitHub Actions
- O GitHub Actions faz:
- Configuração do ambiente de execução (runs-on).
- Definição de uma matriz de versões de Java e Node.js para testar o aplicativo em várias configurações (strategy).
- Checkout do código-fonte (actions/checkout).
- Login no Docker Hub (docker/login-action).
- Configuração do ambiente Node.js (actions/setup-node).
- Instalação de dependências e compilação do frontend (npm install, npm run build).
- Configuração do ambiente Java (actions/setup-java).
- Construção do JAR do aplicativo (mvn clean package).
- Construção da imagem Docker (docker compose build).
- Envio das imagens Docker para o Docker Hub (docker push).
- As imagens estão disponíveis para usar em qualquer ambiente com Docker Instalado.
Tabela de conteúdos
O projeto foi desenvolvido com base na arquitetura em camadas, utilizando padrões de arquitetura REST para garantir uma estrutura organizada e escalável. Nesta arquitetura, a comunicação entre o cliente e o servidor é realizada através do protocolo HTTP, onde o HTTP Client pode ser qualquer Cliente HTTP, como Postman, Insomnia, ou uma aplicação React.
A arquitetura em camadas ajuda a organizar e separar as preocupações da aplicação, facilitando a manutenção, escalabilidade e testabilidade do código. Cada camada possui responsabilidades específicas e claramente definidas, o que torna o código mais modular e fácil de entender.
O padrão REST (Representational State Transfer) é utilizado para definir uma interface uniforme entre os componentes da aplicação, promovendo uma comunicação consistente e eficiente. Isso permite que os recursos da aplicação sejam acessados de maneira padronizada, utilizando os métodos HTTP de forma adequada (GET, POST, PUT, DELETE, etc.) e seguindo os princípios RESTful, como recursos identificáveis por URLs e uso adequado dos códigos de status HTTP.
Além disso, o padrão Value Object foi empregado para garantir a segurança e a integridade dos dados. Ao expor os dados através de objetos de valor intermediários, é possível proteger a estrutura do banco de dados e facilitar a manutenção, evolução e versionamento dos endpoints da API. Por exemplo, ao adicionar uma nova coluna em uma entidade, basta criar outro Value Object, mantendo a compatibilidade com versões anteriores da API.
Na imagem abaixo, apresento uma visão simplificada da arquitetura do projeto, destacando as diferentes camadas e a interação entre elas.
O back-end do projeto fornece as seguintes features:
- Gerar AccessToken:
- Permite aos usuários autenticarem-se na API gerando um AccessToken usando seu
username
epassword
. O AccessToken é um JWT (JSON Web Token) gerado usando um secret-key codificado em base64 e é usado para inicializar o algoritmo HMAC256, que assina os tokens JWT com uma validade de 1 hora.
- Permite aos usuários autenticarem-se na API gerando um AccessToken usando seu
- Atualizar AccessToken Expirado:
- Caso um AccessToken tenha expirado, esta funcionalidade permite decodificar o token com sucesso e gerar um novo token para o usuário.
- Listar todos os livros:
- Recupera todos os livros disponíveis no banco de dados.
- Atualizar um livro:
- Permite atualizar as informações de um livro existente no banco de dados.
- Adicionar um novo livro:
- Permite adicionar um novo livro à coleção do banco de dados.
- Procurar um livro:
- Busca por um livro específico com base no id informado.
- Deletar um livro:
- Remove um livro existente (pelo id) da coleção.
- Listar todas as pessoas:
- Recupera todas as pessoas cadastradas no banco de dados.
- Atualizar uma pessoa:
- Permite atualizar as informações de uma pessoa existente no banco de dados.
- Corrigir uma pessoa:
- Corrige as informações de uma pessoa existente (i.e mudar somente uma informação e não tudo).
- Adicionar uma nova pessoa:
- Permite adicionar uma nova pessoa à base de dados.
- Procurar uma pessoa:
- Busca por uma pessoa específica com base no id.
- Procurar uma pessoa:
- Busca por uma pessoa específica com base em uma parte do nome (e.g nan, retorna "renan", "nando", etc)
- Deletar uma pessoa:
- Remove uma pessoa existente (pelo id) da base de dados.
- Carregar um arquivo e salvar no armazenamento no ambiente de desenvolvimento:
- Permite carregar um arquivo para a API e salvá-lo no ambiente de desenvolvimento.
- Carregar múltiplos arquivos e salvar no armazenamento no ambiente de desenvolvimento:
- Permite carregar vários arquivos para a API e salvá-los no ambiente de desenvolvimento.
- Baixar um arquivo armazenado no ambiente de desenvolvimento:
- Permite baixar um arquivo específico que está armazenado no ambiente de desenvolvimento.
Todos os recursos disponíveis, assim como, as informações necessárias para inserir no corpo do pedido e o retorno das requisições, podem ser vistas no SwaggerHub ou no link do swagger-ui após execução do projeto.
Para obter uma cópia deste repositório e testar as funcionalidades, siga estas simples etapas abaixo.
- Ter instalado o Docker e Docker Compose
Este é o cenário mais simples para subir o ambiente de desenvolvimento com um único comando. Tanto o Client
quanto o Server
são executados dentro de contêineres Docker, além do serviço do banco de dados, o MySQL
.
No arquivo docker-compose.yml
foram feitas as configurações de inicialização dos serviços.
Para obter o código fonte disponível neste repositório, basta executar o comando abaixo:
cd ~
git clone https://github.com/renaner123/springboot_react_mysql.git
Em seguida, o usuário deve fazer o build da composição, executando os comandos abaixo:
cd springboot_react_mysql
docker compose build
Uma vez que esse processo tenha sido finalizado, é preciso iniciar os serviços de banco de dados da composição. Esse processo é realizado por meio do seguinte comando:
docker compose up -d db
É necessário aguardar que o processo anterior tenha sido finalizado, ou seja, o servidor MySQL dentro do contêiner deverá estar pronto para aceitar conexões. Por fim, pode-se executar os demais contêineres da composição com o comando abaixo:
docker compose up
👏 Pronto! A composição está pronta para ser utilizada.
Além da instalação utilizando o build
local, também é possível executar a aplicação sem utilizar o projeto através das imagens disponíveis no Docker Hub (enviadas pelo Actions do GitHub). Para isso, é necessário remover as etapas de build
dos serviços springboot_backend_mysql
e react_app
do arquivo docker-compose.yml
.
Ou seja, para executar a aplicação é necessário apenas ter o docker-compose.yml sem o build e o Docker/Docker Compose instalado.
Para testar a aplicação sem o uso dos contêineres, é necessário ter todo o ambiente de desenvolvimento preparado com:
- Java 21
- Node 20
- MySQL Server 8.3
- Maven 3.8.4
- Git
- Spring Tools Suite (opcional)
- HeidiSQL/MySQL Workbench (opcional) para gerenciar o banco
Com o ambiente preperado, os seguintes passos são necessários para executar o servidor:
cd ~
git clone https://github.com/renaner123/springboot_react_mysql.git
Em seguida, para iniciar o servidor:
cd springboot_react_mysql/springboot_react_mysql/server
Instalar e compilar o projeto
mvn install
Caso queira rodar os testes:
# Todos os testes
mvn test
Iniciar a aplicação e aplicar as migration
mvn spring-boot:run
Caso queira executar o cliente HTTP em React, considereando que ainda está no mesmo diretório, é necessário alterar para o diretório client, instalar as dependências e iniciar a aplicação conforme exemplo abaixo. Lembrando, que essa aplicação não é o foco do projeto.
cd ../client
npm install
npm start
Para testar a aplicação utilizando uma aplicação front-end, foi implementado uma simples aplicação utilizando React, pois não é o foco do projeto. Para fazer o acesso é necessário utilizar a URL do front-end
e se autenticar conforme os dados da tabela abaixo. A aplicação faz o consumo da API utilizando o axios
.
A aplicação React consome os seguintes recursos:
Método | Endpoint | Serviço |
---|---|---|
GET | localhost:80/api/book/v1 | Lista todas os livros cadastrados no banco |
GET | localhost:80/api/book/v1/{id} | Lista as informações de um livro pelo id |
POST | localhost:80/api/book/v1 | Cadastra um novo livro. |
PUT | localhost:80/api/book/v1 | Altera informações de um livro. |
DELETE | localhost:80/api/book/v1/{id} | Deleta um livro pelo id |
POST | localhost:80/auth/signin | Fazer autenticação na aplicação |
Application | URL | Credenciais |
---|---|---|
back-end | http://localhost/swagger-ui/index.html#/ | |
front-end | http://localhost:3000 | renan/admin123 |
Todos os recursos disponíveis, assim como, as informações necessárias para inserir no corpo do pedido e o retorno das requisições, podem ser vistas no SwaggerHub ou no link do swagger-ui.
Para testar todas os recursos do back-end, deixei uma coleção e um environment que podem ser importadas no Postman ou em outras ferramentas que interajam com APIs de maneira eficiente.
Todos os recursos disponíveis, assim como, as informações necessárias para inserir no corpo do pedido e o retorno das requisições, podem ser vistas no SwaggerHub ou no link do swagger-ui.
Contribuições são o que tornam a comunidade de código aberto um lugar tão incrível para aprender, inspirar e criar. Qualquer contribuição que você faça é muito apreciada, de preferência para melhorar a organização, fluídez e boas práticas de projeto.
Se você tiver uma sugestão que possa tornar isso melhor, por favor, faça um fork do repositório e crie um pull request. Você também pode simplesmente abrir uma issue com a tag "melhoria". Não se esqueça de dar uma estrela ao projeto! Obrigado novamente!
- Faça um Fork do projeto
- Crie sua branch de funcionalidade (
git checkout -b feature/AmazingFeature
) - Faça o commit de suas mudanças (
git commit -m 'Adicione alguma AmazingFeature'
) - Faça o push para a branch (
git push origin feature/AmazingFeature
) - Abra um Pull Request
Renan Rodolfo da Silva
Distribuído sob a Licença MIT. Veja LICENSE.txt
para mais informações.