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
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • dTool
  • wikiwiki
  • Wiki
  • guia_desenvolvimento_backend

guia_desenvolvimento_backend · Changes

Page history
Backend development guide (yay! :D) authored Apr 03, 2020 by Rafael Victor Ruwer Araujo's avatar Rafael Victor Ruwer Araujo
Hide whitespace changes
Inline Side-by-side
guia_desenvolvimento_backend.md 0 → 100644
View page @ da7fd675
[Voltar para arquitetura](arquitetura)
# Guia de desenvolvimento - Backend
Este documento é leitura obrigatória antes de iniciar o desenvolvimento do backend. Ele contém informações importantes sobre arquitetura, documentação e organização física do projeto.
**Índice**
- [Organização física](#organização-física)
- [Documentação](#documentação)
- [Arquitetura](#arquitetura)
- [Controllers](#controllers)
- [Funcionamento básico](#funcionamento-básico)
- [Organização física](#organização-física-1)
- [Criando novas controllers](#criando-novas-controllers)
- [Implementando controllers](#implementando-controllers)
- [Services](#services)
- [Organização física](#organização-física-2)
- [Criando novos serviços](#criando-novos-serviços)
- [Implementando serviços](#implementando-serviços)
- [Models (DAOs)](#models-daos)
- [Organização física](#organização-física-3)
- [Criando novos modelos](#criando-novos-modelos)
- [Implementando modelos](#implementando-modelos)
## Organização física
As principais estruturas do projeto são:
- `README.md`: informações sobre o projeto, instruções de configuração do ambiente e documentação dos scripts de execução e manutenção
- `package.json` e `package-lock.json`: gerenciamento de dependências com NPM
- `.[babel,eslint,husky,jest,prettier]rc.js`, `.eslintignore` e `nodemon.json`: configurações de pacotes auxiliares (transpiler, linter, formatter, git hooks, hot reload, testes, ...)
- `.env`: variáveis de ambiente para execução do servidor
- `docs/`: documentação
- `update.js`: script para atualizar a documentação local
- `dTool API.postman_collection_.json`: collection do Postman com requests da API
- `DT.postman_environment.json`: environment do Postman com placeholders para as variáveis
- `DT-development.postman_environment.json`: environment do Postman com valores padrão para desenvolvimento
- `dist/`: código transpilado (que é executado pelo NodeJS)
- `src/`
- `loaders/`: funções de setup da aplicação
- `models/`: modelos/DAOs/persistência ([ver mais](#models-daos))
- `routes/`: controllers/rotas ([ver mais](#controllers))
- `services/`: serviços/negócio ([ver mais](#services))
- `app.js`: ponto de entrada do servidor ("main")
- `config.js`: exporta objeto com variáveis de ambiente (`.env`) para uso pela aplicação
## Documentação
Todas as rotas da aplicação serão documentadas usando o [Postman](https://www.postman.com/). O Postman é uma aplicação que permite a fácil execução de requests HTTP e análise dos retornos, ajudando a testar uma rota durante seu desenvolvimento (se o retorno da rota está de acordo com o especificado na documentação).
Você pode [consultar a documentação das rotas a serem desenvolvidas](https://documenter.getpostman.com/view/10919351/SzYYzJfz?version=latest) pelo navegador e importar a definição das rotas para o aplicativo usando o botão _Run in Postman_. Junto a cada rota, serão anexados exemplos de entrada e retorno esperado, servindo como referência para o desenvolvimento tanto do backend quanto do app.
## Arquitetura
O backend está organizado em uma arquitetura com três camadas:
- controllers (pasta `src/routes`): trata os parâmetros das rotas, utiliza serviços para executar as ações necessárias para o correto funcionamento da rota e controem o retorno da rota (código de status, formato, ...);
- services (pasta `src/services`): camada de negócio, recebe os parâmetros já parseados pelas controllers e usa os DAOs para acesso ao banco de dados;
- models (pasta `src/models`): camada de persistência, provê acesso ao banco de dados.
<p align="center">
<img src="Imagens/arq_backend_basico.png">
</p>
Seguindo o padrão arquitetural em camadas, é importante que objetos de uma camada troquem mensagens apenas com objetos da camada imediatamente inferior, ou objetos da mesma camada. Por exemplo: controllers podem acessar/usar apenas services; services podem usar outros services ou modelos/DAOs (mas não podem acessar controllers).
### Controllers
A camada de controllers (controladoras) é responsável por definir o tratamento para cada rota da API. Elas usam diretamente a API exposta pelo framework [Express](https://expressjs.com/), tratando os parâmetros de cada rota (sejam parâmetros recebidos no body do request, como parte do caminho da rota ou como query), convertendo-os para um formato/estrutura aceito pelo(s) serviço(s) usados, fazendo invocações aos serviços e construindo as respostas de acordo com o retorno dos serviços.
#### Funcionamento básico
1. tratar parâmetros usando API do Express;
2. ajustar parâmetros para formato/estrutura esperada pelo(s) serviço(s) usado(s);
3. executar a(s) chamada(s) ao(s) serviço(s);
4. construir a resposta do request (código de status e payload) a partir da resposta do(s) serviço(s).
#### Organização física
Todas as controllers estão na pasta `src/routes`, e devem ser organizados de acordo com a rota tratada. Por exemplo:
- o arquivo `src/routes/technology.js` trata os requests de todos os verbos aplicáveis (`GET`, `POST`, ...) à rota (e subrotas) `/api/technology`: `GET /api/technology/3`, `POST /api/tecnology`, ...
- da mesma forma, o arquivo `src/routes/healthInstitution.js` cuida da rota `/api/healthInstitution`.
O arquivo `src/routes/index.js` exporta uma função que faz a configuração de todas as rotas da API. Essa função é invocada por um loader como parte do processo de inicialização do servidor.
#### Criando novas controllers
Sempre que for preciso criar o controller para uma nova rota:
- o arquivo do controller deve exportar uma função que recebe um [Router](https://expressjs.com/en/4x/api.html#express.router)
- a função exportada pode ser `async` (`export default async (appRouter) => { ... }`)
- a controller deve ser adicionada ao processo de configuração no arquivo `src/routes/index.js`:
1. importar a controller: `import controller from "./controller"`
2. invocar a função da nova controller: `controller(appRouter)`
#### Implementando controllers
Os serviços que podem ser usados pelas controllers estão na pasta `src/services`, e devem ser importádos de lá.
> **Importante**
>
> Para manter a padronização, um serviço **não** deve ser importado a partir do arquivo onde está definido, mas apenas do arquivo de onde todos os serviços são exportados:
>
> - ❌ `import AlphaService from "../services/AlphaService"`
> - ✅ `import { AlphaService } from "../services"`
O acesso a serviços é feito com o uso de um [_service locator_](https://en.wikipedia.org/wiki/Service_locator_pattern): um objeto central que instancia e provê os serviços para uso pelas controllers. Para usar um serviço, é preciso:
1. importar o service locator: `import { Container } from "typedi"` (estamos usando o pacote [typedi](https://www.npmjs.com/package/typedi))
2. importar a classe do serviço: `import { AlphaService } from "../services"`
3. obter uma referência ao serviço: `const alphaService = Container.get(AlphaService)`
### Services
A camada de serviços é responsável pela lógica de negócio da aplicação. Ela faz as validações necessárias sobre os parâmetros, "joga" (`throw`) erros para tratamento pelas controllers, e faz modificações no banco de dados quando necessário. Um serviço também pode usar outro(s) serviço(s) para seu funcionamento.
Geralmente, um serviço é responsável pelas regras de negócio relacionadas a uma entidade de negócio. Por exemplo: `HealthInstitutionService` agrupa regras relativas às instituições de saúde; `TechnologyService`, relativos às tecnologias (procedimentos); e assim por diante.
> **Nota**
>
> Ainda não há uma definição exata quanto à granularidade e limite de responsabilidades dos serviços. Isso será discutido ao longo do projeto, caso a caso.
#### Organização física
Todos os serviços estão na pasta `src/services`. Serviços que podem ser usados por controllers devem ser exportados no arquivo `src/services/index.js`.
#### Criando novos serviços
Sempre que for necessário criar um novo serviço:
1. criar um arquivo com o nome da classe do serviço: `src/services/BetaService.js`
2. criar e exportar a classe do serviço: `export default class BetaService { ... }`
3. re-exportar o novo serviço no arquivo `src/services/index.js`: `export { default as BetaService } from "./BetaService"`
#### Implementando serviços
Não é possível definir uma regra geral de formato de implementação dos serviços: depende do objetivo do método e entidade relacionada. Entretanto, alguns métodos CRUD de serviços possuem uma implementação parecida:
1. validação das entradas
2. invocação de alguma operação da camada de modelos (_create_, _recover_, _update_, _delete_, ...)
3. filtro sobre o retorno da camada de serviço para retorno à controller
**Ressaltando:** não há um esqueleto de como é a implementação de um método de serviço.
### Models (DAOs)
A camada de modelos encapsula a persistência dos dados e comunicação com o banco de dados. Os objetos dessa camada também são chamados de DAO (_Data Access Object_), por conta do [padrão de projeto que implementam](https://en.wikipedia.org/wiki/Data_access_object).
Como o backend comunica-se com o SGBD PostgreSQL, essa camada é desenvolvida com o pacote [Sequelize](https://sequelize.org/), que faz o processo de mapeamento entre os modelos relacional e orientado a objetos (processo conhecido como [ORM](https://en.wikipedia.org/wiki/Object-relational_mapping)).
O uso do Sequelize como ORM permite acelerar o desenvolvimento ao não ter que implementar métodos CRUD simples que o Sequelize já provê, com _create_, _list_, _update_, entre outros.
Essa camada está intimamente ligada ao modelo físico de armazenamento dos dados no PostgreSQL: a definição de um modelo depende das tabelas, seus campos, chave primária e chaves estrangeiras (relacionamentos).
#### Organização física
Todos os modelos devem ficar na pasta `src/models`. O nome do arquivo de definição de cada modelo deve ser composto pelo nome do modelo (em _UpperCammelCase_), seguido de `DAO`. Cada arquivo deve definir apenas um modelo.
#### Criando novos modelos
Supondo que seja preciso criar um modelo para representar uma pessoa:
1. criar um arquivo `src/models/PersonDAO.js`
2. adicionar os imports necessários do Sequelize: `import { Model, DataTypes } from "sequelize"`
3. exportar uma classe _default_ que herda da classe `Model` do Sequelize: `export default class PersonDAO extends Model { ... }` (geralmente não há métodos customizados na classe; mais na próxima seção)
4. exportar uma função, de nome `setup`, que recebe como parâmetro o objeto do Sequelize para definição do modelo: `export const setup = (sequelize) => { ... }`
5. definir o modelo dentro da função `setup` usando a API do Sequelize.
#### Implementando modelos
Geralmente, não é preciso implementar operações customizadas na maioria dos modelos, apenas as operações providas pelo Sequelize são suficientes (_create_, _list_, _delete_, ...).
Entretanto, se necessário, é possível criar métodos customizados na classe do modelo:
```js
export default class PersonDAO extends Model {
static performComplexQuery(parameters) {
...
}
}
```
Clone repository
  • arquitetura
  • banco_dados
  • configuracao
  • docs usuario
  • gerenciamento_projeto
  • guia_desenvolvimento_backend
  • Home
  • instalacao
  • materiais_estudo
  • mockups
  • requisitos
  • reunioes
  • sprints
  • time