diff --git a/README.md b/README.md index 5e1e1b1..6a88248 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ Prototype of a .NET 8 Web API for a Library system This project demonstrates how to build a RESTful API using **.NET 8**, following modern best practices for architecture, testing, and maintainability. It simulates a simple library system with authors and books, and is designed for learning and demonstration purposes. +In addition to traditional CRUD operations, the project features an event-driven checkout workflow (EDA) using RabbitMQ and MassTransit, enabling asynchronous order processing and service decoupling. + ## Table of Contents - [Features & Best Practices](#features--best-practices) @@ -32,6 +34,10 @@ It simulates a simple library system with authors and books, and is designed for - [Stop the services](#stop-the-services) - [Observability - Main packages used](#observability---main-packages-used) - [Containers summary](#containers-summary) +- [EDA: Messaging and Event-Driven Architecture](#eda-messaging-and-event-driven-architecture) +- [Architecture Overview](#architecture-overview) +- [Example: Checkout Event Flow](#example-checkout-event-flow) +- [Observability: Tracing & Metrics](#observability-tracing--metrics) - [License](#license) ## Features & Best Practices @@ -46,6 +52,8 @@ It simulates a simple library system with authors and books, and is designed for - **Consistent and centralized error handling** with RFC-compliant `ApiProblemDetails` responses - **Unit and integration tests** (xUnit, Moq, FluentAssertions), with mocks to isolate dependencies - **Automatic API documentation** with Swagger/OpenAPI +- **Event-Driven Architecture (EDA)** using RabbitMQ and MassTransit for asynchronous communication between services +- **Message-based workflow** for checkout and order processing - **Separation of concerns** and SOLID principles - **Environment-based configuration** via `appsettings.json` - **Lowercase URLs** and JSON serialization options for cleaner APIs @@ -64,17 +72,25 @@ Before running the API for the first time, restore the project dependencies: dotnet restore ``` -### Running the API - +### 1. Run Only the API (Authors/Books) +For quick local development or unit testing of authors and books: ```sh dotnet run --project src/Library.API/Library.API.csproj ``` +The API will be available at https://localhost:5001. + +> **Note:** Order/checkout endpoints require RabbitMQ and the full stack running. -The API will be available at `https://localhost:5001` (or as configured). +### 2. Run the Full Stack (Recommended for Orders/Checkout) +To test the event-driven order flow, messaging, and observability: +```sh +docker compose up --build +``` +This will start the API, Checkout worker, RabbitMQ, and all observability tools. ### API Documentation -After running, access Swagger UI at: +The API documentation is available via Swagger UI at: `https://localhost:5001/swagger` ### Automated Tests @@ -129,10 +145,8 @@ Example of manual test workflow in the `.http` file: - List books - Update a book - Remove book and author - -#### Additional Tip - -Ensure the API is running (`dotnet run`) before performing any manual tests. +- Create a book order (checkout) +- Check the status of a book order ### Running Code Coverage @@ -146,18 +160,20 @@ reportgenerator -reports:"tests/**/TestResults/**/coverage.opencover.xml" -targe ### Project Structure ``` -src/Library.API/ # Main API project - Controllers/ # API endpoints - Domain/ # Domain models, repositories, services - Infrastructure/ # EF Core context, repositories, services - DTOs/ # Data Transfer Objects - Validation/ # Custom validation attributes - Mapping/ # AutoMapper profiles -tests/Library.API.Tests/ # Unit tests +src/Library.API/ # Main API project + Controllers/ # API endpoints + Domain/ # Domain models, repositories, services + DTOs/ # Data Transfer Objects + Extensions/ # Extension methods and helpers + Infrastructure/ # EF Core context, repositories, services, middlewares + Mapping/ # AutoMapper profiles + Validation/ # Custom validation attributes +src/Library.Events/ # Event contracts (messages shared between services) +src/Library.Checkout/ # Worker service for processing order events +tests/Library.API.Tests/ # Unit tests tests/Library.API.IntegrationTests/ # Integration tests -observability/ # Observability configs (Grafana dashboards, Prometheus, Loki, provisioning) +observability/ # Observability configs (Grafana dashboards, Prometheus, Loki, provisioning) ``` - ### Continuous Integration and Deployment (CI/CD) #### Workflow Overview @@ -198,11 +214,9 @@ The project implements a comprehensive and automated Continuous Integration and - Automatic Docker image generation - Code coverage tracking -**Note**: Deployment requires configured Docker Hub credentials in GitHub Secrets. - ### Observability with Jaeger, Prometheus, Loki and Grafana -To run the API together with Jaeger, Prometheus, Loki, Promtail, and Grafana, use the `docker-compose.yml` file: +To run the API together with Jaeger, Prometheus, Loki, Promtail, Grafana, and the Otel Collector, use the `docker-compose.yml` file: #### Start all observability services @@ -224,6 +238,17 @@ docker compose up --build docker compose down ``` +#### Containers summary + +- **otel-collector**: Receives traces, metrics, and logs from the services and forwards them to Jaeger, Prometheus, Loki, and other observability tools. +- **rabbitmq**: Message broker used for event-driven communication between services (management UI at http://localhost:15672, default user/password: guest/guest). +- **library-api**: Main .NET API, exposes REST endpoints, metrics, and logs. +- **jaeger**: Collector and visualizer for distributed traces (OpenTelemetry/Jaeger). +- **prometheus**: Metrics collector and database, scrapes the API's /metrics endpoint. +- **loki**: Backend for storing and indexing structured logs. +- **promtail**: Log collector, reads logs from containers and sends them to Loki. +- **grafana**: Centralized visualization for metrics, logs, and traces (dashboards, queries, alerts). + #### Observability - Main packages used - `OpenTelemetry.Exporter.OpenTelemetryProtocol` (for Jaeger via OTLP) @@ -231,16 +256,54 @@ docker compose down - `OpenTelemetry.Extensions.Hosting` - `OpenTelemetry.Instrumentation.AspNetCore` - `OpenTelemetry.Instrumentation.Http` +- `OpenTelemetry.Instrumentation.MassTransit` (for distributed tracing of messaging) - `Serilog.AspNetCore` and `Serilog.Enrichers.Span` (structured logs) -#### Containers summary +### Architecture Overview -- **library-api**: Your main .NET API, exposes REST endpoints, metrics, and logs. -- **jaeger**: Collector and visualizer for distributed traces (OpenTelemetry/Jaeger). -- **prometheus**: Metrics collector and database, scrapes the API's /metrics endpoint. -- **loki**: Backend for storing and indexing structured logs. -- **promtail**: Log collector, reads logs from containers and sends them to Loki. -- **grafana**: Centralized visualization for metrics, logs, and traces (dashboards, queries, alerts). +The system is based on Event-Driven Architecture (EDA) using RabbitMQ and MassTransit. The main flow is: + +The event-driven workflow relies on RabbitMQ as the central message broker, running as a container in the stack. + +``` +[Client] ---> [Library.API] --(OrderPlacedEvent)--> [RabbitMQ] --(OrderPlacedEvent)--> [Library.Checkout] + ^ | | + | |<--(Status events: PaymentConfirmed, | + | | OrderProcessing, OrderShipped, OrderDelivered, | + | | OrderCompleted, PaymentFailed) | + | | | + |<-------------------(Status update via API)-----------------------| +``` + +- **Library.API**: Exposes REST endpoints, publishes events to RabbitMQ, and updates order status based on events. +- **Library.Checkout**: Worker service that consumes events from RabbitMQ, processes business logic (payment, shipping), and emits new events. +- **Library.Events**: Shared project with event/message contracts. + +#### EDA: Messaging and Event-Driven Architecture - Main packages used + +- `MassTransit` (core library for distributed application messaging) +- `MassTransit.RabbitMQ` (RabbitMQ transport for MassTransit) +- `OpenTelemetry.Instrumentation.MassTransit` (distributed tracing for messaging) + +## Example: Checkout Event Flow + +Before creating a book order, you need to: + +1. Create an Author +2. Create a Book (using the authorId from the previous response) + +After that, you can: + +- Create a Book Order (using the bookId from the previous response) +- The API will publish an OrderPlacedEvent to RabbitMQ +- The Checkout service will process the event and emit the following events: PaymentConfirmed, PaymentFailed, OrderProcessing, OrderShipped, OrderDelivered, and OrderCompleted. +- You can check the order status via the API + +## Observability: Tracing & Metrics + +- **Jaeger**: http://localhost:16686 — visualize distributed traces for each order event. +- **Grafana**: http://localhost:3000 — dashboards for metrics and traces. +- **Prometheus**: http://localhost:9090 — raw metrics. ## License diff --git a/README.pt-br.md b/README.pt-br.md index b1909a0..e09784b 100644 --- a/README.pt-br.md +++ b/README.pt-br.md @@ -14,6 +14,8 @@ Protótipo de uma Web API .NET 8 para um sistema de biblioteca Este projeto demonstra como construir uma API RESTful usando **.NET 8**, seguindo boas práticas modernas de arquitetura, testes e manutenibilidade. Simula um sistema simples de biblioteca com autores e livros, e foi projetado para fins de aprendizado e demonstração. +Além das operações CRUD tradicionais, o projeto conta com um fluxo de checkout orientado a eventos (EDA) usando RabbitMQ e MassTransit, permitindo processamento assíncrono de pedidos e desacoplamento entre serviços. + ## Sumário - [Funcionalidades & Boas Práticas](#funcionalidades--boas-práticas) @@ -32,6 +34,10 @@ Simula um sistema simples de biblioteca com autores e livros, e foi projetado pa - [Parar os serviços](#parar-os-serviços) - [Observabilidade - Principais pacotes utilizados](#observabilidade---principais-pacotes-utilizados) - [Resumo dos containers](#resumo-dos-containers) +- [EDA: Mensageria e Arquitetura Orientada a Eventos - Principais pacotes utilizados](#eda-mensageria-e-arquitetura-orientada-a-eventos---principais-pacotes-utilizados) +- [Visão Geral da Arquitetura](#visão-geral-da-arquitetura) +- [Exemplo: Fluxo de Checkout por Eventos](#exemplo-fluxo-de-checkout-por-eventos) +- [Observabilidade: Tracing & Métricas](#observabilidade-tracing--métricas) - [Licença](#licença) ## Funcionalidades & Boas Práticas @@ -46,6 +52,8 @@ Simula um sistema simples de biblioteca com autores e livros, e foi projetado pa - **Tratamento de erros consistente e centralizado** com respostas RFC-compliant `ApiProblemDetails` - **Testes unitários e de integração** (xUnit, Moq, FluentAssertions), com mocks para isolar dependências - **Documentação automática da API** com Swagger/OpenAPI +- **Arquitetura Orientada a Eventos (EDA)** usando RabbitMQ e MassTransit para comunicação assíncrona entre serviços +- **Fluxo de checkout baseado em mensagens** - **Separação de responsabilidades** e princípios SOLID - **Configuração baseada em ambiente** via `appsettings.json` - **URLs minúsculas** e opções de serialização JSON para APIs mais limpas @@ -64,27 +72,27 @@ Antes de rodar a API pela primeira vez, restaure as dependências do projeto: dotnet restore ``` -### Executando a API - +### 1. Rodar apenas a API (Autores/Livros) +Para desenvolvimento local rápido ou testes unitários de autores e livros: ```sh dotnet run --project src/Library.API/Library.API.csproj ``` +A API estará disponível em https://localhost:5001. + +> **Nota:** Os endpoints de pedidos/checkout exigem o RabbitMQ e o stack completo em execução. -A API estará disponível em `https://localhost:5001` (ou conforme configurado). +### 2. Rodar o Stack Completo (Recomendado para Pedidos/Checkout) +Para testar o fluxo orientado a eventos, mensageria e observabilidade: +```sh +docker compose up --build +``` +Isso irá iniciar a API, o worker Checkout, o RabbitMQ e todas as ferramentas de observabilidade. ### Documentação da API -Após rodar, acesse o Swagger UI em: +A documentação da API está disponível via Swagger UI em: `https://localhost:5001/swagger` -### Executando os testes - -Os testes unitários e de integração estão localizados no diretório `tests/`. - -```sh -dotnet test -``` - ### Testes Automatizados O projeto inclui cobertura abrangente de testes. Testes unitários e de integração estão localizados no diretório `tests/`. @@ -137,10 +145,8 @@ Exemplo de fluxo de testes manuais no arquivo `.http`: - Listar livros - Atualizar livro - Remover livro e autor - -#### Dica Adicional - -Certifique-se de que a API esteja rodando (`dotnet run`) antes de realizar qualquer teste manual. +- Criar um pedido de livro (checkout) +- Consultar o andamento do pedido de livro ### Gerando relatório de cobertura de código @@ -154,16 +160,19 @@ reportgenerator -reports:"tests/**/TestResults/**/coverage.cobertura.xml" -targe ### Estrutura do Projeto ``` -src/Library.API/ # Projeto principal da API - Controllers/ # Endpoints da API - Domain/ # Modelos de domínio, repositórios, serviços - Infrastructure/ # Contexto EF Core, repositórios, serviços - DTOs/ # Objetos de Transferência de Dados - Validation/ # Atributos de validação customizados - Mapping/ # Perfis do AutoMapper -tests/Library.API.Tests/ # Testes unitários +src/Library.API/ # Projeto principal da API + Controllers/ # Endpoints da API + Domain/ # Modelos de domínio, repositórios, serviços + DTOs/ # Objetos de Transferência de Dados + Extensions/ # Métodos de extensão e helpers + Infrastructure/ # Contexto EF Core, repositórios, serviços, middlewares + Mapping/ # Perfis do AutoMapper + Validation/ # Atributos de validação customizados +src/Library.Events/ # Contratos de eventos (mensagens compartilhadas entre serviços) +src/Library.Checkout/ # Serviço worker para processamento de eventos de pedidos +tests/Library.API.Tests/ # Testes unitários tests/Library.API.IntegrationTests/ # Testes de integração -observability/ # Configurações de observabilidade (dashboards Grafana, Prometheus, Loki, provisionamento) +observability/ # Configurações de observabilidade (dashboards Grafana, Prometheus, Loki, provisionamento) ``` ### Integração Contínua e Deploy (CI/CD) @@ -206,11 +215,9 @@ O projeto implementa um pipeline de Integração Contínua e Deploy (CI/CD) abra - Geração automática de imagem Docker - Rastreamento de cobertura de código -**Nota**: O deploy requer credenciais configuradas do Docker Hub nos Secrets do GitHub. - ### Observabilidade com Jaeger, Prometheus, Loki e Grafana -Para rodar a API junto com Jaeger, Prometheus, Loki, Promtail e Grafana, utilize o arquivo `docker-compose.yml`: +Para rodar a API junto com Jaeger, Prometheus, Loki, Promtail, Grafana e o Otel Collector, utilize o arquivo `docker-compose.yml`: #### Subir todos os serviços de observabilidade @@ -232,6 +239,17 @@ docker compose up --build docker compose down ``` +#### Resumo dos containers + +- **otel-collector**: Recebe traces, métricas e logs dos serviços e encaminha para o Jaeger, Prometheus, Loki e outras ferramentas de observabilidade. +- **rabbitmq**: Message broker utilizado para comunicação orientada a eventos entre os serviços (painel de administração em http://localhost:15672, usuário/senha padrão: guest/guest). +- **library-api**: API .NET principal, expõe endpoints REST, métricas e logs. +- **jaeger**: Coletor e visualizador de traces distribuídos (OpenTelemetry/Jaeger). +- **prometheus**: Coletor e banco de dados de métricas, faz scraping do endpoint /metrics da API. +- **loki**: Backend de armazenamento e indexação de logs estruturados. +- **promtail**: Coletor de logs, lê logs dos containers e envia para o Loki. +- **grafana**: Visualização centralizada de métricas, logs e traces (dashboards, queries, alertas). + #### Observabilidade - Principais pacotes utilizados - `OpenTelemetry.Exporter.OpenTelemetryProtocol` (para Jaeger via OTLP) @@ -239,17 +257,55 @@ docker compose down - `OpenTelemetry.Extensions.Hosting` - `OpenTelemetry.Instrumentation.AspNetCore` - `OpenTelemetry.Instrumentation.Http` +- `OpenTelemetry.Instrumentation.MassTransit` (para tracing distribuído de mensageria) - `Serilog.AspNetCore` e `Serilog.Enrichers.Span` (logs estruturados) -#### Resumo dos containers +### Visão Geral da Arquitetura -- **library-api**: Sua API .NET principal, expõe endpoints REST, métricas e logs. -- **jaeger**: Coletor e visualizador de traces distribuídos (OpenTelemetry/Jaeger). -- **prometheus**: Coletor e banco de dados de métricas, faz scraping do endpoint /metrics da API. -- **loki**: Backend de armazenamento e indexação de logs estruturados. -- **promtail**: Coletor de logs, lê logs dos containers e envia para o Loki. -- **grafana**: Visualização centralizada de métricas, logs e traces (dashboards, queries, alertas). +O sistema é baseado em Arquitetura Orientada a Eventos (EDA) usando RabbitMQ e MassTransit. O fluxo principal é: + +O fluxo orientado a eventos depende do RabbitMQ como broker central de mensagens, rodando como container no stack. + +``` +[Cliente] ---> [Library.API] --(OrderPlacedEvent)--> [RabbitMQ] --(OrderPlacedEvent)--> [Library.Checkout] + ^ | | + | |<--(Eventos de status: PaymentConfirmed, | + | | OrderProcessing, OrderShipped, OrderDelivered, | + | | OrderCompleted, PaymentFailed) | + | | | + |<-------------------(Atualização de status via API)---------------| +``` + +- **Library.API**: Expõe endpoints REST, publica eventos no RabbitMQ e atualiza status do pedido conforme eventos. +- **Library.Checkout**: Serviço worker que consome eventos do RabbitMQ, processa lógica de negócio (pagamento, envio) e emite novos eventos. +- **Library.Events**: Projeto compartilhado com contratos de eventos/mensagens. + +### EDA: Mensageria e Arquitetura Orientada a Eventos - Principais pacotes utilizados + +- `MassTransit` (biblioteca principal para mensageria distribuída) +- `MassTransit.RabbitMQ` (transporte RabbitMQ para o MassTransit) +- `OpenTelemetry.Instrumentation.MassTransit` (tracing distribuído para mensageria) + +### Exemplo: Fluxo de Checkout por Eventos + +Antes de criar um pedido de livro, é necessário: + +1. Criar um Autor +2. Criar um Livro (usando o authorId da resposta anterior) + +Depois disso, você pode: + +- Criar um Pedido de Livro (usando o bookId da resposta anterior) +- A API irá publicar um OrderPlacedEvent no RabbitMQ +- O serviço Checkout processará o evento e emitirá os seguintes eventos: PaymentConfirmed, PaymentFailed, OrderProcessing, OrderShipped, OrderDelivered e OrderCompleted. +- Você pode consultar o status do pedido pela API + +### Observabilidade: Tracing & Métricas + +- **Jaeger**: http://localhost:16686 — visualize traces distribuídos de cada evento do pedido. +- **Grafana**: http://localhost:3000 — dashboards de métricas e traces. +- **Prometheus**: http://localhost:9090 — métricas brutas. -## Licença +### Licença -MIT \ No newline at end of file +MIT