Skip to content

This project was built as a result of a deepening of the studies discussed on the blog farlley.com with a greater focus on Domain Driven Design (DDD) architecture. In this work you will find a simple template for creating microservices, as well as a use case (which will still be implemented according to the Roadmap found in this same document) a…

License

Notifications You must be signed in to change notification settings

farlleyferreira/ms-fastapi-template

Repository files navigation

FastApi Microservices Template

Resumo

Este projeto foi construído como resultado de um aprofundamento dos estudos discutidos no blog farlley.com com foco maior na arquitetura Domain Driven Design (DDD). Neste trabalho você encontrará um template simples para criação de microsserviços, bem como um caso de uso (que ainda será implementado de acordo com o Roadmap que se encontra neste mesmo documento) aplicando as teorias e estudos apresentados nos livros Implementando Domain-Driven Design - Vaughn Vernon, Domain-Driven Design: Atacando as Complexidades no Coração do Software - Eric Evans, e Building Microservices: Designing Fine-Grained Systems - Sam Newman, a bibliografia consultada será adicionada ao final deste documento em acordo com o roadmap da aplicação. O template foi escrito para a linguagem python em sua versão 3.9.0, utilizando o framework FastApi. Para a camada de testes utilizamos a biblioteca PyTest. Nossa aplicação faz ainda integração com os seguintes serviços:

  • Mongo DB
  • Elasticsearch
  • Rabbit MQ
  • Redis

Ao longo do desenvolvimento do projeto, outras integrações poderão ser adicionadas, desde que, sejam feitas respeitando as diretrizes e arquitetura adotadas neste projeto base, com a finalidade de manter sua integridade. Todos os itens pertinentes a arquitetura e estrutura do projeto serão extensivamente discutidos nos itens que estão contidos neste mesmo documento. Sinta-se a vontade para contribuir com o mesmo.

Roadmap


  1. Criação do manual de requisitos para PR.
  2. Implantação de mais casos de uso.

Setup

Este projeto está estruturado em docker, utilizamos o docker-compose para montar o processo de startup dos serviços os quais a aplicação necessita para rodar. A configuração desses serviços bem como sua estrutura, serão melhor discutidos na seção Estrutura e padrões adotados.

Para rodar todas as aplicações via docker-compose.

  1. Realize o clone desta aplicação para seu diretório de projetos
  2. Dentro deste diretório será possível verificar a criação da pasta: ms-fastapi-template
  3. Abra o diretório ms-fastapi-template/api/
  4. Neste diretório você encontrará o arquivo .env
  5. Para cada serviço contido neste arquivo, altere o host: localhost para o nome do serviço desejado (nome do serviço no arquivo docker-compose).

Obs: Neste arquivo estão as configurações de ambiente do nosso projeto e não, eu optei por não criar um arquivo .ENV por motivos que discutiremos melhor na seção Estrutura e padrões adotados.

Trecho Original:

rabbitmq:
  host: "localhost"
  port: 5672
  username: "farlley_ferreira"
  password: "mstemplate123"

Trecho Ajustado:

rabbitmq:
  host: "rabbit"
  port: 5672
  username: "farlley_ferreira"
  password: "mstemplate123"

  1. Após ajustar o arquivo para todos os serviços desejados, o usuário deverá rodar o comando:

docker-compose up

    Ou em alguns casos

sudo docker-compose up

Se os ajustes tiverem sido feitos de forma adequada a aplicação irá iniciar no endereço http://localhost:5000: e sua documentação via swagger estará ativa via http://localhost:5000/docs


Para rodar somente o projeto ms-template localmente e o restante via docker-compose.

  1. Realize o clone desta aplicação para seu diretório de projetos
  2. Certifique-se de possuir o make instalado em seu OS
  3. Crie um ambiente virtual utilizando gerenciador de sua preferência > (pyenv, virtualenv, anaconda...).
  4. Dentro deste diretório será possível verificar a criação da pasta: ms-fastapi-template
  5. No arquivo docker-compose.yml, dentro deste diretório deverá ser comentado o item referente ao serviço da com tag: web.
  6. Aponte seu terminal para o diretório api, dessa mesma aplicação e execute o comando:

make install-requeriments

    ou caso não possua o make, poderá rodar o comando:

pip install -r requirements.txt

  1. Se todos os pacotes foram instalados corretamente você poderá executar:

docker-compose up

    Ou em alguns casos

sudo docker-compose up

  1. Com todos os procedimentos tendo sido executados corretamente você poderá executar:

make run

    ou caso não possua o make, poderá rodar o comando:

python setup.py

Nossa aplicação estará então disponível para ser utilizada no endereço http://localhost:5000: e sua documentação via swagger estará ativa via http://localhost:5000/docs

Para rodar a suíte de testes:

  1. Com todos os procedimentos anteriores tendo sido executados corretamente:

make test-coverage

    ou caso não possua o make, poderá rodar o comando:

pytest --cov-report term-missing --cov=project/

Ou ainda, de acordo com a preferência do desenvolvedor, os testes poderão ser executados via plugin da sua IDE ou editor de códigos preferida, recomendo a Python Test Explorer for Visual Studio Code ou ainda Test Explorer UI. Já para os testes do tipo BDD que utilizaremos nos casos de uso, recomendo Pytest BDD

Ops

Sonar Qube

Para garantir a qualidade de código e boas práticas foi adicionado ao projeto uma imagem do SonarQube, a qual pode ser executada através dos seguintes comandos:

cd ops

docker-compose up

Feito isso, será necessário realizar o download do sonar scanner adequado ao seu sistema operacional, como este projeto foi desenvolvido em um ambiente windows (#mejulgue), você encontrará neste mesmo diretório, a versão para este sistema operacional.

Volte a raiz do projeto, e novamente aponte para o diretório api e execute o comando:

make sonar-scaner

Este comando executará todas as análises pertinentes e realizará o upload do relatório para o servidor do sonar, que poderá ser acessado em: http://localhost:9000. Você poderá observar que dentro do diretório api, será possível encontrar um arquivo denominado sonar-project.properties, que deverá ser alterado de acordo com seu objetivo e a documentação do SonarQube

Estrutura: 🔍


  - ms-fastapi-template
  |   - api
  |   |   - project
  |   |   |   - helpers
  |   |   |   - infrastructure
  |   |   |   |   - constants
  |   |   |   |   - drivers
  |   |   |   |   - monitoring_layer
  |   |   |   |   - open_api
  |   |   |   |   - logs
  |   |   |   - domain
  |   |   |   - resources
  |   |   |   - routers
  |   |   - tests
  |   |   |   - helpers
  |   |   |   - infrastructure
  |   |   |   |   - constants
  |   |   |   |   - drivers
  |   |   |   |   - open_api
  |   |   |   |   - logs
  |   |   |   - domain
  |   |   |   - resources
  |   |   - dockerfile
  |   |   - makefile
  |   |   - requirements.txt
  |   |   - setup
  |   - ops
  |   - worker
  |   - volumes
  |   - docker-compose.yml

Diagrama geral da aplicação: 👷

alt text

Padrões adotados: 📈

O projeto foi concebido de forma a simplificar o de api's, tendo como base o cenário de microsserviços. Neste template, centralizamos em "infrastructure" todos os componentes que possam servir o domínio, seja conexões com bancos de dados, serviços de cache distribuído ou qualquer tipo de integração com serviços externos e suas derivações. Possibilitando maior liberdade para que o desenvolvedor trabalhe no que de fato importa, que é a implementação da camada de negocio.

Resources.

  • Schemas.

    Responsável por modelar os objetos de requisição e respostas expostos pela api. Deverão ser utilizadas de modo a não gerar qualquer tipo de dependência das camadas de modelo de dados, mesmo que em alguns casos possa exibir certo nível de semelhança com os modelos contidos no repositório, em função de isolar sua utilização.

  • Controllers.

    Responsável por expor os recursos disponíveis ao serviço. Não devem em hipótese alguma possuir qualquer tipo de regra de negócio, sendo responsáveis apenas pelo controle do recurso, no contexto de repassar as requisições ao serviço e, retornar a devida resposta ao item solicitado.

Domain.

  • Business Rules.

    Responsável por processar uma determinada requisição e aplicar as regras de negócio ao dado co0ntexto da requisição, utilizando a ou as, modelos necessárias para executar os processos desejados, com suporte do modulo de validações (caso necessário).

  • Repository.

    Responsável por conter a representação do domínio na forma de objetos que podem ser do tipo entidade ou objeto de valor. Em contextos específicos, poderão existir particularidades que implementem validações em banco de dados, ou mesmo, validações referentes a tipagem, formatação, entre outros. As validações poderão seguir o padrão do Pydantic, através de Field's, ou ainda métodos customizados assim como você poderá encontrar nos projetos contidos na pasta demo. Os modelos poderão ainda ser construídos utilizando o dataclasses vide documentação (dataclass).

  • Validations.

    Responsável por conter todo e qualquer tipo de regra de validação a ser utilizada por um determinado objeto ou regra de negócio. Escolhemos separar as funcionalidades de validação de forma a tornar o código escrito na camada de regras de negócio mais limpo e desacoplado possivel.

Infrastructure.

  • Constants.

    Responsável por conter todas as variáveis constantes em relação ao projeto, tais como, nomes de recursos de bancos de dados (tabelas, collections, procedures), e outras constantes que poderão ser armazenadas.

  • Data Layer.

    Responsável por expor na forma de adaptador, as funcionalidades de bancos de dados contidos no projeto, seja via ORM, ou execução direta de comandos. Esta camada não deverá conter qualquer tipo de regra negócio ou similar, servindo única e exclusivamente como uma interface que abstrai a comunicação com o banco de dados.

  • Drivers.

    Responsável por expor mecanismos de comunicação através de um adaptador com qualquer tipo de serviço externo, via conector, seja a conexão com um banco de dados, api, serviço de mensageria, cache distribuído e etc. As conexões com as dependências externas deverão ser executadas única e exclusivamente através da classe connector do driver em contexto, e expostas através da classe adapter, onde poderão existir métodos de encapsulamento de funções especificas, assim como healthchecks.

  • dotenv.

    Responsável por conter as variaveis de ambiente do projeto, por padrão, está definida para um arquivo yaml, esta decisão foi tomada com a intenção de facilitar algumas integrações com kubernetes.

  • Monitoring Layer.

    Responsável por abstrair as funcionalidades de log e monitoramento da aplicação. Caso desejar, poderá realizar a integração com outros serviços, tais como new relic, dynatrace, entre outros.

  • Open Api.

    Responsável por abstrair e estender as funcionalidades de customização e inicialização do Open Api Specification.

Helpers.

Responsável por prover algoritmos de uso geral ao domínio (algoritmos de busca, strategy's, e outras estruturas), devendo ser consumido exclusivamente na camada Domain.

Observações: ℹ️

Pontos importantes:

  • Este template foi construído para atender as necessidades de um ambiente de microsserviços, entretanto, poderá perfeitamente ser utilizado em uma arquitetura monolítica, sem alterações do padrão aqui apresentado.

  • Toda e qualquer integração com serviços externos deverão ser feitas através da configuração de um driver, que deverá realizar a integração através de um connector e expor as funcionalidades desejadas através de um adapter. Está medida foi tomada de forma a simplificar a disposição destes recursos.

  • Não deverão existir quaisquer regras de negócio fora da camada Domain, afinal, ela tem a finalidade de isolar e manter simples a implementação de novas funcionalidades, sem contaminar as camadas mais externas da aplicação.

  • Todas as abstrações da camada Data Layer deverão ser implementações utilizando ORM, executores de procedimentos encapsulados em banco de dados (os quais em teoria não deveriam conter regras de negocio, apenas de armazenamento), ou por fim implementações DSL para acesso a dados.

  • Os métodos adicionados em Helpers deverão ser consumidos na camada Domain, não havendo necessidade do seu consumo em outros módulos do sistema, portanto deverá ser mantido o padrão de seu consumo apenas na camada indicada.

Bibliografia utilizada: 📚

  1. COCKBURN, A. Hexagonal architecture. alistair.cockburn.us.
  2. EVANS, E. Domain-Driven Design: Tackling Complexity in the Heart of Software. Addison-Wesley.
  3. FOWLER, M; et al. Patterns of Enterprise Application Architecture. Addison-Wesley.
  4. FOWLER, S. J. Production-Ready Microservices: Building Standardized Systems Across an Engineering Organization. O'REILLY Media Inc.
  5. KLEPPMANN, M. Designing Data-Intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems. O'REILLY Media Inc.
  6. MARTIN, R. C; HENNEY, K. Clean Architecture: A Craftsman's Guide to Software Structure and Design. Pearson.
  7. MARTIN, R. C; WAMPLER, D. Clean Code: A Handbook of Agile Software Craftsmanship. Pearson.
  8. NEWMAN, S. Building Microservices, Designing Fine-Grained Systems. O'REILLY Media Inc.
  9. VERNON, V. Implementing Domain-Driven Design. Addison-Wesley.

About

This project was built as a result of a deepening of the studies discussed on the blog farlley.com with a greater focus on Domain Driven Design (DDD) architecture. In this work you will find a simple template for creating microservices, as well as a use case (which will still be implemented according to the Roadmap found in this same document) a…

Topics

Resources

License

Stars

Watchers

Forks