Skip to content

GitLab

  • Menu
Projects Groups Snippets
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in
  • Wiki Wiki
  • Project information
    • Project information
    • Activity
    • Labels
    • Planning hierarchy
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 0
    • Issues 0
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 0
    • Merge requests 0
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Monitor
    • Monitor
    • Metrics
    • Incidents
  • Packages & Registries
    • Packages & Registries
    • Package Registry
    • Infrastructure Registry
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Sem Barreiras
  • WikiWiki
  • Wiki
  • backend

backend · Changes

Page history
Atualiza documentacao Backend authored Mar 21, 2024 by Fernanda Ferreira de Mello's avatar Fernanda Ferreira de Mello
Show whitespace changes
Inline Side-by-side
backend.md
View page @ ee56dd8a
| [Home](home) | [**Escopo**](escopo) | [Processo](processo) | [Design/Mockups](design_mockups) | [Configuração](configuracao) | [Arquitetura](arquitetura) | [Gerência](gerencia) | [BD](Banco de Dados) | [Qualidade](qualidade) | [Frontend](frontend) | [Backend](backend) | [Home](home) | [**Escopo**](escopo) | [Processo](processo) | [Design/Mockups](design_mockups) | [Configuração](configuracao) | [Arquitetura](arquitetura) | [Gerência](gerencia) | [BD](Banco de Dados) | [Qualidade](qualidade) | [Frontend](frontend) | [Backend](backend) |
| :----------: | :-------------------------------: | :------------------: | :--------------: | :--------------------------: | :--------------------: | :------------------------: | :--------------: | :--------------------: | :---------------: | :--------------------: | | :----------: | :------------------: | :------------------: | :------------------------------: | :--------------------------: | :------------------------: | :------------------: | :------------------: | :--------------------: | :------------------: | :----------------: |
# Backend # Backend
...@@ -7,15 +7,38 @@ Esta página centraliza informações sobre o [repositório Backend do projeto S ...@@ -7,15 +7,38 @@ Esta página centraliza informações sobre o [repositório Backend do projeto S
## Sumário ## Sumário
- [Escolha de tecnologias](#escolha-de-tecnologias)
- [Organização do repositório](#organização-do-repositório) - [Organização do repositório](#organização-do-repositório)
- [Padrões de código](#padrões-de-código) - [Padrões de código](#padrões-de-código)
- [Nomenclatura de classes](#nomenclatura-de-classes) - [Nomenclatura de classes](#nomenclatura-de-classes)
- [Nomenclatura de variáveis](#nomenclatura-de-variáveis) - [Nomenclatura de variáveis](#nomenclatura-de-variáveis)
- [Nomenclatura de métodos](#nomenclatura-de-métodos) - [Nomenclatura de métodos](#nomenclatura-de-métodos)
- [Padrões das APIs REST](#padrões-das-apis-rest)
- [Checkstyle](#checkstyle)
- [Tratamento de exceções](#tratamento-de-exceções) - [Tratamento de exceções](#tratamento-de-exceções)
- [Validação de parâmetros das requisições](#validação-de-parâmetros-das-requisições) - [Validação de parâmetros das requisições](#validação-de-parâmetros-das-requisições)
- [Documentação do Swagger](#documentação-do-swagger) - [Documentação do Swagger](#documentação-do-swagger)
## Escolha de tecnologias
Conforme mencionado na página de configuração de ambiente da Wiki, como tecnologias de Backend foram selecionadas a linguagem Java, junto ao framework Spring Boot, para o desenvolvimento da API, e o banco de dados PostgreSQL.
Esta decisão foi tomada com base em dois momentos. Em um primeiro momento, na primeira semana da Sprint 0, cada integrante citou as tecnologias com as quais tinha experiência e com qual _stack_ tinha mais interesse em trabalhar (Frontend ou Backend) ao se apresentar. Este levantamento demonstrou que, dentre as 16 pessoas AGES 1,2 e 3 do time:
- 9 pessoas tinham experiência com Java (principalmente devido às cadeiras obrigatórias do curso de Engenharia de Software);
- 11 pessoas tinham experiência com JavaScript;
- 4 pessoas tinham experiência com JavaScript e TypeScript;
- 2 pessoas tinham experiência com Python;
- 1 pessoa tinha experiência com Ruby.
Dentre essas 5 alternativas de tecnologia para Backend, a equipe avaliou que faria mais sentido considerar as 3 primeiras (Java, JavaScript, e JavaScript + TypeScript), dado que existiria uma curva de aprendizado menor por grande parte do time já ter utilizado ou visto códigos destas tecnologias anteriormente. Além disso, tanto o Java quanto o JavaScript possuem frameworks conhecidos para o desenvolvimento de APIs Backend (Spring Boot e Node.js com Express), o que implica em muitos materiais didáticos e gratuitos para estudo na Internet.
Diante disso, em um segundo momento, após a apresentação dos _stakeholders_ no dia 08/03/2024, foi realizada uma enquete pelos AGES 3 para que os colegas votassem na tecnologia com a qual tinham interesse em trabalhar, e esta enquete ficou ativa até o dia 11/03/2024. Abaixo, é possível ver os resultados da enquete, de modo que se percebe que as tecnologias mais votadas foram aquelas escolhidas para o projeto:
<img src="./resources/images/resultados-enquete-backend-framework.png" width="450">
<img src="./resources/images/resultados-enquete-backend-db.png" width="450">
## Organização do repositório ## Organização do repositório
O projeto Spring Boot do repositório de Backend do projeto está organizado seguindo um padrão _Controller-Service-Repository_, e esse padrão está refletido na organzação de pacotes do projeto. Optou-se por esse padrão pois, ainda que este padrão possa trazer problemas como acoplamento de regras de negócio e tecnologias de ORM (sendo estes problemas que poderiam ser resolvidos com um padrão de arquitetura limpa), ele segmenta o código em camadas visando uma separação de preocupações/responsabilidades (_Separation of concerns_). Além disso, é um padrão fácil de entender para desenvolvedores que não possuem muita experiência com Spring Boot ou com o desenvolvimento de APIs em geral. O projeto Spring Boot do repositório de Backend do projeto está organizado seguindo um padrão _Controller-Service-Repository_, e esse padrão está refletido na organzação de pacotes do projeto. Optou-se por esse padrão pois, ainda que este padrão possa trazer problemas como acoplamento de regras de negócio e tecnologias de ORM (sendo estes problemas que poderiam ser resolvidos com um padrão de arquitetura limpa), ele segmenta o código em camadas visando uma separação de preocupações/responsabilidades (_Separation of concerns_). Além disso, é um padrão fácil de entender para desenvolvedores que não possuem muita experiência com Spring Boot ou com o desenvolvimento de APIs em geral.
...@@ -23,16 +46,16 @@ O projeto Spring Boot do repositório de Backend do projeto está organizado seg ...@@ -23,16 +46,16 @@ O projeto Spring Boot do repositório de Backend do projeto está organizado seg
Diante disso, os pacotes do projeto estão divididos da forma abaixo: Diante disso, os pacotes do projeto estão divididos da forma abaixo:
- :file_folder: `config`: Configurações personalizadas da aplicação (ex.: configuração da conexão com o banco de dados, declaração de Beans). - :file_folder: `config`: Configurações personalizadas da aplicação (ex.: configuração da conexão com o banco de dados, declaração de Beans).
- :file_folder: `controller`: Expõe pontos de entrada para comunicação com o mundo exterior. Neste projeto, gerencia a API REST da aplicação, incluindo responsabilidades como autenticação e autorização, e delega o processamento de lógica de negócio para a camada de _services_. - :file*folder: `controller`: Expõe pontos de entrada para comunicação com o mundo exterior. Neste projeto, gerencia a API REST da aplicação, incluindo responsabilidades como autenticação e autorização, e delega o processamento de lógica de negócio para a camada de \_services*.
- :file_folder: `dto`: Classes utilizadas para transferir dados entre camadas de uma aplicação (não são entidades, são apenas classes que modelam essas informações a serem trafegadas na aplicação). - :file_folder: `dto`: Classes utilizadas para transferir dados entre camadas de uma aplicação (não são entidades, são apenas classes que modelam essas informações a serem trafegadas na aplicação).
- :file_folder: `request`: DTOs para dados de entrada das requisições. - :file_folder: `request`: DTOs para dados de entrada das requisições.
- :file_folder: `response`: DTOs para dados de resposta das requisições. - :file_folder: `response`: DTOs para dados de resposta das requisições.
- :file_folder: `exception`: Exceções personalizadas da aplicação. - :file_folder: `exception`: Exceções personalizadas da aplicação.
- :file_folder: `model`: Entidades do negócio. - :file_folder: `model`: Entidades do negócio.
- :file_folder: `repository`: Encapsula a lógica de acesso ao banco de dados para buscar e persistir dados. - :file_folder: `repository`: Encapsula a lógica de acesso ao banco de dados para buscar e persistir dados.
- :file_folder: `impl`: Classes que implementam as interfaces em _repository_. - :file*folder: `impl`: Classes que implementam as interfaces em \_repository*.
- :file_folder: `service`: Implementação da lógica de negócio (interfaces). Se necessário buscar ou salvar dados, delega isso para a camada de _repository_. - :file*folder: `service`: Implementação da lógica de negócio (interfaces). Se necessário buscar ou salvar dados, delega isso para a camada de \_repository*.
- :file_folder: `impl`: Classes que implementam as interfaces em _service_. - :file*folder: `impl`: Classes que implementam as interfaces em \_service*.
- :file_folder: `util`: Classes e métodos utilitários (ex.: formatação de datas) - :file_folder: `util`: Classes e métodos utilitários (ex.: formatação de datas)
## Padrões de código ## Padrões de código
...@@ -40,12 +63,14 @@ Diante disso, os pacotes do projeto estão divididos da forma abaixo: ...@@ -40,12 +63,14 @@ Diante disso, os pacotes do projeto estão divididos da forma abaixo:
### Nomenclatura de classes ### Nomenclatura de classes
Classes do projeto devem ser nomeadas em inglês e seguir o padrão **PascalCase**, ou seja, devem iniciar com letra maiúscula e cada palavra ou abreviatura no meio da frase também deve iniciar com letra maiúscula. Por exemplo: Classes do projeto devem ser nomeadas em inglês e seguir o padrão **PascalCase**, ou seja, devem iniciar com letra maiúscula e cada palavra ou abreviatura no meio da frase também deve iniciar com letra maiúscula. Por exemplo:
- UserController :heavy_check_mark: - UserController :heavy_check_mark:
- User_Controller :x: - User_Controller :x:
- Usercontroller :x: - Usercontroller :x:
- userController :x: - userController :x:
Além disso, com exceção do pacote model, os nomes das classes devem refletir o pacote onde elas estão localizadas, conforme o exemplo abaixo: Além disso, com exceção do pacote model, os nomes das classes devem refletir o pacote onde elas estão localizadas, conforme o exemplo abaixo:
- :file_folder: config: ExemploConfig - :file_folder: config: ExemploConfig
- :file_folder: controller: ExemploController - :file_folder: controller: ExemploController
- :file_folder: dt.request: ExemploRequest - :file_folder: dt.request: ExemploRequest
...@@ -58,14 +83,16 @@ Além disso, com exceção do pacote model, os nomes das classes devem refletir ...@@ -58,14 +83,16 @@ Além disso, com exceção do pacote model, os nomes das classes devem refletir
### Nomenclatura de variáveis ### Nomenclatura de variáveis
Variáveis devem ser nomeadas em inglês e seguir o padrão **camelCase**, ou seja, devem iniciar com letra minúscula e cada palavra ou abreviatura no meio da frase deve iniciar com letra maiúscula. Por exemplo: Variáveis devem ser nomeadas em inglês e seguir o padrão **camelCase**, ou seja, devem iniciar com letra minúscula e cada palavra ou abreviatura no meio da frase deve iniciar com letra maiúscula. Por exemplo:
- isAdmin :heavy_check_mark: - isAdmin :heavy_check_mark:
- isadmin :x: - isadmin :x:
- is_Admin :x: - is_Admin :x:
- IsAdmin :x: - IsAdmin :x:
A exceção são as variáveis constantes (que devem ser estáticas e finais) e enums, que devem seguir o padrão **SCREAMING_SNAKE_CASE**, onde as palavras no meio da frase são separadas por *underscores* (_) e as letras devem ser todas maiúsculas. Por exemplo: API_BASE_URL A exceção são as variáveis constantes (que devem ser estáticas e finais) e enums, que devem seguir o padrão **SCREAMING_SNAKE_CASE**, onde as palavras no meio da frase são separadas por _underscores_ (\_) e as letras devem ser todas maiúsculas. Por exemplo: API_BASE_URL
Além disso, para criar um código limpo e fácil de entender e realizar a manutenção depois, sempre nomeie as variáveis de forma que fique claro o seu propósito/o tipo de informação que ela possui. Para isso, seguem algumas dicas: Além disso, para criar um código limpo e fácil de entender e realizar a manutenção depois, sempre nomeie as variáveis de forma que fique claro o seu propósito/o tipo de informação que ela possui. Para isso, seguem algumas dicas:
- Evitar abreviações. - Evitar abreviações.
- Para variáveis booleanas, não nomear apenas com substantivos, para deixar claro que é um booleano. Por exemplo, ao invés de "publish", usem "isPublished". - Para variáveis booleanas, não nomear apenas com substantivos, para deixar claro que é um booleano. Por exemplo, ao invés de "publish", usem "isPublished".
- Criar variáveis fáceis de pronunciar. - Criar variáveis fáceis de pronunciar.
...@@ -75,22 +102,49 @@ Além disso, para criar um código limpo e fácil de entender e realizar a manut ...@@ -75,22 +102,49 @@ Além disso, para criar um código limpo e fácil de entender e realizar a manut
### Nomenclatura de métodos ### Nomenclatura de métodos
Variáveis devem ser nomeadas em inglês e seguir o padrão **camelCase**, ou seja, devem iniciar com letra minúscula e cada palavra ou abreviatura no meio da frase deve iniciar com letra maiúscula. Por exemplo: Variáveis devem ser nomeadas em inglês e seguir o padrão **camelCase**, ou seja, devem iniciar com letra minúscula e cada palavra ou abreviatura no meio da frase deve iniciar com letra maiúscula. Por exemplo:
- findUserByName :heavy_check_mark: - findUserByName :heavy_check_mark:
- finduserbyname :x: - finduserbyname :x:
- find_User_By_Name :x: - find_User_By_Name :x:
- FindUserByName :x: - FindUserByName :x:
Além disso, para facilitar a leitura do código, em uma classe os métodos sempre devem estar organizados na ordem abaixo: Além disso, para facilitar a leitura do código, em uma classe os métodos sempre devem estar organizados na ordem abaixo:
1. Métodos `public` 1. Métodos `public`
2. Métodos `protected` 2. Métodos `protected`
3. Métodos `private` 3. Métodos `private`
### Padrões das APIs REST
A API desenvolvida para este projeto deverá seguir o estilo de arquitetura REST, muito utilizado para o desenvolvimento de APIs web, e para isso algumas restrições e boas práticas devem ser seguidos. Neste estilo, as informações gerenciadas pela aplicação e que possuem uma identificação única são chamadas de recursos (pode-se dizer que são mapeamentos conceituais/abstratos às entidades da aplicação), e as URIs da aplicação (_Uniform Resource Identifiers_) devem referenciar estes recursos de forma clara e padronizada.
Abaixo segue um exemplo de uma API fictícia para ilustrar o padrão que deve ser utilizado pela aplicação:
- **GET /v1/books** - buscar lista/coleção de livros
- **GET /v1/books/1** - buscar um livro específico a partir de um identificador único
- **POST /v1/books** - criar/registrar um novo livro
- **PATCH /v1/books/1** - editar um livro específico a partir de um identificador único (atualizações parciais)
- **PUT /v1/books/1** - editar um livro específico a partir de um identificador único (substituindo a representação do recurso pelos novos dados informados)
- **DELETE /v1/books/1** - deletar um livro específico a partir de um identificador único
Os recursos devem ser referenciados como substantivos no plural, e também deve se adicionar o versionamento da API no começo do *path*, conforme exemplos acima.
Além disso, caso exista algum recurso que precise ser representado com mais de uma palavra, estas devem ser separadas por hífens, por exemplo: **/v1/loan-contracts**
Para mais informações, sugere-se a leitura [deste link](https://www.alura.com.br/artigos/rest-principios-e-boas-praticas), que traz algumas boas práticas de forma didática.
### Checkstyle
Para estabelecer padrões e regras de codificação no projeto, e verificar de forma fácil se o código escrito está aderente a estas regras ou não, estabeleceu-se no projeto o uso da ferramenta Checkstyle, que realiza uma análise de código estático e aponta os pontos do código implementado onde ocorreram violações dos padrões. Para este projeto, foi habilitada a verificação das convenções de "Sun's Java Style", que podem ser vistas nesta [documentação](https://checkstyle.org/sun_style.html).
As instruções de como executar a análise do Checkstyle no projeto podem ser vistas no [README do repositório de Backend](https://tools.ages.pucrs.br/sem-barreiras/sembarreiras-backend/-/blob/main/README.md#checando-padr%C3%B5es-de-codifica%C3%A7%C3%A3o).
## Tratamento de exceções ## Tratamento de exceções
No projeto, dentro do pacote `config`, existe a classe `GlobalExceptionHandler`, que foi criada para que as exceções lançadas pela a aplicação durante a execução sejam tratadas e retornadas com um corpo de resposta e status HTTP de resposta apropriados. No projeto, dentro do pacote `config`, existe a classe `GlobalExceptionHandler`, que foi criada para que as exceções lançadas pela a aplicação durante a execução sejam tratadas e retornadas com um corpo de resposta e status HTTP de resposta apropriados.
Em casos de erro, o corpo da resposta deve sempre seguir um formato padronizado, conforme exemplo abaixo. Este formato é aquele modelado pela classe `ErrorResponse`. Em casos de erro, o corpo da resposta deve sempre seguir um formato padronizado, conforme exemplo abaixo. Este formato é aquele modelado pela classe `ErrorResponse`.
```json ```json
{ {
"error": "Mensagem da excecao" "error": "Mensagem da excecao"
...@@ -108,12 +162,14 @@ Para mais informações, leia [esta documentação do Spring](https://spring.io/ ...@@ -108,12 +162,14 @@ Para mais informações, leia [esta documentação do Spring](https://spring.io/
Ao receber uma nova requisição, é importante verificar se os parâmetros necessários vieram preenchidos de forma completa e com valores que façam sentido. Uma forma na qual se pode fazer isso é utilizando a API de validação de Beans do Java. Ao receber uma nova requisição, é importante verificar se os parâmetros necessários vieram preenchidos de forma completa e com valores que façam sentido. Uma forma na qual se pode fazer isso é utilizando a API de validação de Beans do Java.
A API disponibiliza várias anotações que podem ser utilizadas para validar diferentes cenários, a exemplo de: A API disponibiliza várias anotações que podem ser utilizadas para validar diferentes cenários, a exemplo de:
- @NotNull: verifica se a variável/atributo é nulo. - @NotNull: verifica se a variável/atributo é nulo.
- @NotBlank: verifica se a variável/atributo String é nulo ou é uma String vazia. - @NotBlank: verifica se a variável/atributo String é nulo ou é uma String vazia.
- @Min: verifica se a variável/atributo tem valor igual ou maior que o valor mínimo informado. - @Min: verifica se a variável/atributo tem valor igual ou maior que o valor mínimo informado.
- @Max: verifica se a variável/atributo tem valor igual ou menor que o valor máximo informado. - @Max: verifica se a variável/atributo tem valor igual ou menor que o valor máximo informado.
Supondo um cenário onde existe um *endpoint* de uma aplicação de biblioteca, para registro de novos livros, onde se recebe um corpo de requisição JSON, para realizar a validação precisariam ser feitos os ajustes abaixo: Supondo um cenário onde existe um _endpoint_ de uma aplicação de biblioteca, para registro de novos livros, onde se recebe um corpo de requisição JSON, para realizar a validação precisariam ser feitos os ajustes abaixo:
1. Na classe DTO que modela os dados do corpo da requisição, adicionar as anotações nos atributos que se deseja validar. 1. Na classe DTO que modela os dados do corpo da requisição, adicionar as anotações nos atributos que se deseja validar.
```java ```java
public class BookRequest { public class BookRequest {
...@@ -126,19 +182,19 @@ Supondo um cenário onde existe um *endpoint* de uma aplicação de biblioteca, ...@@ -126,19 +182,19 @@ Supondo um cenário onde existe um *endpoint* de uma aplicação de biblioteca,
} }
``` ```
2. Adicionar a anotação @Valid no método do controller onde se recebe o corpo da requisição. 2. Adicionar a anotação @Valid no método do controller onde se recebe o corpo da requisição.
```java `java
@PostMapping @PostMapping
public BookResponse createBook(@Valid @RequestBody BookRequest bookRequest) { public BookResponse createBook(@Valid @RequestBody BookRequest bookRequest) {
... ...
} }
``` `
Para mais informações, leia [esta página](https://www.baeldung.com/java-validation). Para mais informações, leia [esta página](https://www.baeldung.com/java-validation).
## Documentação do Swagger ## Documentação do Swagger
A ferramenta Swagger (OpenAPI) já foi configurada na aplicação, para documentação da API e para permitir testar requisições HTTP via interface gráfica. Diante disso, novos *controllers* REST que forem criados já vão ser exibidos na [url do Swagger](http://localhost:8080/swagger-ui/index.html) sem precisar de nenhuma configuração adicional. A ferramenta Swagger (OpenAPI) já foi configurada na aplicação, para documentação da API e para permitir testar requisições HTTP via interface gráfica. Diante disso, novos _controllers_ REST que forem criados já vão ser exibidos na [url do Swagger](http://localhost:8080/swagger-ui/index.html) sem precisar de nenhuma configuração adicional.
No entanto, para garantir que a API esteja bem documentada, sugere-se utilizar as anotações da API do Swagger para descrever melhor quais são os propósitos de cada *endpoint* e quais são os significados de cada parâmetro de requisição e código de resposta. Seguem alguns exemplos de anotação abaixo: No entanto, para garantir que a API esteja bem documentada, sugere-se utilizar as anotações da API do Swagger para descrever melhor quais são os propósitos de cada _endpoint_ e quais são os significados de cada parâmetro de requisição e código de resposta. Seguem alguns exemplos de anotação abaixo:
- @Operation: usada para descrever uma operação no Swagger (adicionar resumo, tags, etc) - @Operation: usada para descrever uma operação no Swagger (adicionar resumo, tags, etc)
- @Parameter: usada para descrever um parâmetro de uma requisição HTTP (propósito do parâmetro, exemplo de valor, etc) - @Parameter: usada para descrever um parâmetro de uma requisição HTTP (propósito do parâmetro, exemplo de valor, etc)
......
Clone repository
  • Banco de Dados
  • Sprint 0
  • Sprint 1
  • Sprint 2
  • Sprint 3
  • Sprint 4
  • arquitetura
  • backend
  • configuracao
  • design_mockups
  • escopo
  • frontend
  • gerencia
  • Home
  • processo
View All Pages