https://github.com/eneas-almeida/bridge
📜O projeto Bridge é uma arquitetura de microserviços desenvolvida por Enéas Almeida, composta por dois serviços principais que se comunicam via gRPC
https://github.com/eneas-almeida/bridge
clean-architecture grpc java microservices spring-boot webflux
Last synced: 27 days ago
JSON representation
📜O projeto Bridge é uma arquitetura de microserviços desenvolvida por Enéas Almeida, composta por dois serviços principais que se comunicam via gRPC
- Host: GitHub
- URL: https://github.com/eneas-almeida/bridge
- Owner: eneas-almeida
- Created: 2025-12-16T21:59:08.000Z (6 months ago)
- Default Branch: master
- Last Pushed: 2025-12-26T18:53:54.000Z (6 months ago)
- Last Synced: 2025-12-28T00:37:11.955Z (6 months ago)
- Topics: clean-architecture, grpc, java, microservices, spring-boot, webflux
- Homepage:
- Size: 52.7 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Bridge - Documentação da Arquitetura
## Visão Geral
O projeto **Bridge** é uma arquitetura de microserviços composta por dois serviços principais que se comunicam via **gRPC**:
- **API Service**: Gateway REST que expõe endpoints HTTP e se comunica com o serviço People via gRPC
- **People Service**: Serviço backend que fornece dados de usuários via gRPC, com suporte a múltiplas fontes de dados externas (JSONPlaceholder ou DummyJSON)
```
┌──────────────┐ HTTP/REST ┌──────────────┐ gRPC ┌──────────────┐ HTTP ┌─────────────────┐
│ Cliente │ ─────────────────> │ API Service │ ──────────────> │People Service│ ────────────> │ External APIs │
│ (Browser) │ │ (Port 8081) │ │ (Port 9090) │ │ - JSONPlaceholder│
└──────────────┘ └──────────────┘ └──────────────┘ │ - DummyJSON │
└─────────────────┘
```
---
## Índice
1. [Tecnologias Utilizadas](#tecnologias-utilizadas)
2. [Arquitetura dos Serviços](#arquitetura-dos-serviços)
3. [Contrato gRPC](#contrato-grpc)
4. [Fluxo de Comunicação Detalhado](#fluxo-de-comunicação-detalhado)
5. [API Service](#api-service)
6. [People Service](#people-service)
7. [Configuração e Execução](#configuração-e-execução)
8. [Endpoints Disponíveis](#endpoints-disponíveis)
---
## Tecnologias Utilizadas
### Comuns a Ambos os Projetos
- **Java 21**
- **Spring Boot 3.3.3**
- **Spring WebFlux** (Programação Reativa)
- **Project Reactor** (Mono/Flux)
- **Lombok**
- **Maven**
**API Service:**
- **gRPC 1.58.0**
- **Protocol Buffers 3.24.3**
**People Service:**
- **gRPC 1.59.0**
- **Protocol Buffers 3.24.4**
### Específicas do API Service
- **gRPC Client Spring Boot Starter 2.15.0**
- **MapStruct 1.5.5** (Mapeamento gRPC Proto para DTOs)
### Específicas do People Service
- **gRPC Server Spring Boot Starter 2.15.0**
- **Reactor gRPC 1.2.4** (gRPC Reativo)
- **MapStruct 1.5.5** (Mapeamento de DTOs)
- **Logstash Logback Encoder 7.4** (Logging estruturado)
- **Datadog Trace API 1.30.1** (Observabilidade)
---
## Arquitetura dos Serviços
Ambos os serviços seguem os princípios de **Clean Architecture** com separação clara de responsabilidades:
### Camadas da Arquitetura
```
┌─────────────────────────────────────────────┐
│ Presentation/Entrypoint │
│ (REST Controllers / gRPC Services) │
└────────────────┬────────────────────────────┘
│
┌────────────────▼────────────────────────────┐
│ Application Layer │
│ (Services + DTOs) │
└────────────────┬────────────────────────────┘
│
┌────────────────▼────────────────────────────┐
│ Domain Layer │
│ (Repository/Client Interfaces) │
└────────────────┬────────────────────────────┘
│
┌────────────────▼────────────────────────────┐
│ Infrastructure Layer │
│ (Repositories / gRPC Clients/Servers) │
│ (HTTP Clients / Mappers) │
└─────────────────────────────────────────────┘
```
---
## Contrato gRPC
O contrato de comunicação entre os serviços é definido através de **Protocol Buffers**.
### Arquivo Proto (`person.proto`)
```protobuf
syntax = "proto3";
option java_package = "com.people.grpc";
option java_outer_classname = "ServiceProto";
package grpcservice;
service PeopleService {
rpc GetPeople (PeopleRequestGrpc) returns (PeopleResponseGrpc);
rpc ListPeople (ListPeopleRequestGrpc) returns (ListPeopleResponseGrpc);
}
message PeopleRequestGrpc {
int32 id = 1;
}
message ListPeopleRequestGrpc {}
message PeopleResponseGrpc {
int32 id = 1;
string name = 2;
string email = 3;
}
message ListPeopleResponseGrpc {
repeated PeopleResponseGrpc people = 1;
}
```
### RPCs Disponíveis
| RPC | Request | Response | Descrição |
|-----|---------|----------|-----------|
| `GetPeople` | `PeopleRequestGrpc` (id) | `PeopleResponseGrpc` | Busca uma pessoa por ID |
| `ListPeople` | `ListPeopleRequestGrpc` (vazio) | `ListPeopleResponseGrpc` | Lista todas as pessoas |
---
## Fluxo de Comunicação Detalhado
### Fluxo 1: Buscar Pessoa por ID
```
Cliente API Service People Service External API
│ │ │ (DummyJSON ou JSONPlaceholder)
│ GET /api/peoples/1 │ │ │
├──────────────────────>│ │ │
│ │ PeopleController │ │
│ │ ↓ │ │
│ │ PeopleService │ │
│ │ ↓ │ │
│ │ PeopleRepository │ │
│ │ ↓ │ │
│ │ PeopleGrpcClient │ │
│ │ (MapStruct) │ │
│ │ │ │
│ │ gRPC: GetPeople(id=1) │ │
│ ├───────────────────────>│ │
│ │ │ PeopleGrpcService │
│ │ │ ↓ │
│ │ │ PeopleService │
│ │ │ ↓ │
│ │ │ PeopleRepository │
│ │ │ (Strategy Pattern) │
│ │ │ ↓ │
│ │ │ DummyClient ou │
│ │ │ TypiCodeClient │
│ │ │ (MapStruct) │
│ │ │ │
│ │ │ GET /users/1 │
│ │ ├───────────────────────>│
│ │ │ │
│ │ │ JSON Response │
│ │ │<───────────────────────┤
│ │ │ │
│ │ │ Map to DTO │
│ │ │ (PeopleResponse) │
│ │ │ │
│ │ PeopleResponse (gRPC) │ │
│ │<───────────────────────┤ │
│ │ │ │
│ │ Map Proto to DTO │ │
│ │ (MapStruct) │ │
│ │ ↓ │ │
│ │ PeopleResponse (DTO) │ │
│ │ │ │
│ JSON Response │ │ │
│<──────────────────────┤ │ │
```
### Fluxo 2: Listar Todas as Pessoas
```
Cliente API Service People Service External API
│ │ │ (DummyJSON ou JSONPlaceholder)
│ GET /api/peoples │ │ │
├──────────────────────>│ │ │
│ │ PeopleController │ │
│ │ ↓ │ │
│ │ PeopleService │ │
│ │ ↓ │ │
│ │ PeopleRepository │ │
│ │ ↓ │ │
│ │ PeopleGrpcClient │ │
│ │ (MapStruct) │ │
│ │ │ │
│ │ gRPC: ListPeople() │ │
│ ├───────────────────────>│ │
│ │ │ PeopleGrpcService │
│ │ │ ↓ │
│ │ │ PeopleService │
│ │ │ ↓ │
│ │ │ PeopleRepository │
│ │ │ (Strategy Pattern) │
│ │ │ ↓ │
│ │ │ DummyClient ou │
│ │ │ TypiCodeClient │
│ │ │ (MapStruct) │
│ │ │ │
│ │ │ GET /users │
│ │ ├───────────────────────>│
│ │ │ │
│ │ │ JSON Array Response │
│ │ │<───────────────────────┤
│ │ │ │
│ │ │ Map to Flux │
│ │ │ (MapStruct) │
│ │ │ │
│ │ ListPeopleResponse │ │
│ │ (repeated gRPC) │ │
│ │<───────────────────────┤ │
│ │ │ │
│ │ Map Proto to Flux │ │
│ │ (MapStruct) │ │
│ │ │ │
│ JSON Array Response │ │ │
│<──────────────────────┤ │ │
```
---
## API Service
### Estrutura do Projeto
```
api/
├── src/main/java/org/api/
│ ├── presentation/
│ │ └── controller/
│ │ └── PeopleControllerImpl.java
│ ├── application/
│ │ ├── dto/
│ │ │ └── PeopleResponse.java
│ │ └── service/
│ │ ├── PeopleService.java (Interface)
│ │ └── PeopleServiceImpl.java
│ ├── domain/
│ │ ├── client/
│ │ │ └── PeopleServiceClient.java (Interface)
│ │ └── repository/
│ │ └── PeopleRepository.java (Interface)
│ └── infrastructure/
│ ├── client/
│ │ ├── PeopleServiceGrpcClientImpl.java
│ │ └── PeopleGrpcMapper.java (MapStruct)
│ ├── repository/
│ │ └── PeopleRepositoryImpl.java
│ └── config/
│ └── RepositoryConfig.java
├── src/main/proto/
│ └── person.proto
└── src/main/resources/
└── application.yml
```
### Componentes Principais
#### 1. PeopleControllerImpl (`presentation/controller/PeopleControllerImpl.java`)
```java
@RestController
@RequestMapping("/api/peoples")
@RequiredArgsConstructor // Lombok
public class PeopleControllerImpl {
private final PeopleService peopleService; // Interface!
@GetMapping("/{id}")
public Mono getPeopleById(@PathVariable int id)
@GetMapping
public Flux listPeople()
}
```
**Responsabilidades:**
- Expor endpoints REST HTTP
- Receber requisições do cliente
- Delegar para o serviço de aplicação
- Retornar DTOs de resposta
- **Inversão de Dependência:** Injeta interface `PeopleService`, não implementação
#### 2. PeopleService (`application/service/`)
**PeopleService (Interface)**
```java
public interface PeopleService {
Mono getById(int id);
Flux listAll();
}
```
**PeopleServiceImpl**
```java
@Service
@RequiredArgsConstructor // Lombok
public class PeopleServiceImpl implements PeopleService {
private final PeopleRepository peopleRepository;
@Override
public Mono getById(int id) {
return peopleRepository.findById(id);
}
@Override
public Flux listAll() {
return peopleRepository.findAll();
}
}
```
**Responsabilidades:**
- Orquestrar a lógica de negócio
- Delegar para o repositório
- Camada de abstração entre controller e infraestrutura
#### 3. PeopleRepositoryImpl (`infrastructure/repository/PeopleRepositoryImpl.java`)
```java
@RequiredArgsConstructor // Lombok
public class PeopleRepositoryImpl implements PeopleRepository {
private final PeopleServiceClient peopleClient;
@Override
public Mono findById(int id) {
return peopleClient.getPeopleById(id);
}
@Override
public Flux findAll() {
return peopleClient.listPeople();
}
}
```
**Responsabilidades:**
- Implementar a interface `PeopleRepository`
- Delegar para o cliente gRPC
- Abstrair a comunicação gRPC
#### 4. PeopleServiceGrpcClientImpl (`infrastructure/client/PeopleServiceGrpcClientImpl.java`)
```java
@Component
@RequiredArgsConstructor // Lombok
public class PeopleServiceGrpcClientImpl implements PeopleServiceClient {
@GrpcClient("people-service")
private PeopleServiceGrpc.PeopleServiceBlockingStub peopleServiceStub;
private final PeopleGrpcMapper peopleGrpcMapper; // MapStruct!
@Override
public Mono getPeopleById(int id) {
return Mono.fromCallable(() -> {
ServiceProto.PeopleRequestGrpc request =
ServiceProto.PeopleRequestGrpc.newBuilder()
.setId(id)
.build();
ServiceProto.PeopleResponseGrpc response =
peopleServiceStub.getPeople(request);
return peopleGrpcMapper.toPeopleResponse(response); // MapStruct
})
.subscribeOn(Schedulers.boundedElastic());
}
}
```
**Responsabilidades:**
- Implementar a interface `PeopleServiceClient`
- Realizar chamadas gRPC para o People Service
- Converter chamadas bloqueantes em streams reativos (Mono/Flux)
- Mapear protobuf messages para DTOs usando **MapStruct**
#### 5. PeopleGrpcMapper (`infrastructure/client/PeopleGrpcMapper.java`)
```java
@Mapper(
componentModel = "spring",
implementationName = "PeopleGrpcMapperImpl"
)
public interface PeopleGrpcMapper {
@Mapping(target = "id", source = "id")
@Mapping(target = "name", source = "name")
@Mapping(target = "email", source = "email")
PeopleResponse toPeopleResponse(ServiceProto.PeopleResponseGrpc response);
}
```
**Responsabilidades:**
- Mapeamento **type-safe** de gRPC Proto para DTO
- Geração de código em tempo de compilação via MapStruct
- Integração com Spring via `componentModel = "spring"`
### Configuração (`application.yml`)
```yaml
server:
port: 8081
spring:
application:
name: api
grpc:
client:
people-service:
address: 'static://127.0.0.1:9090'
negotiationType: PLAINTEXT
enable-keep-alive: true
keep-alive-without-calls: true
max-inbound-message-size: 4194304 # 4 MB
```
---
## People Service
### Estrutura do Projeto
```
people/
├── src/main/java/org/people/
│ ├── PeopleApplication.java
│ ├── domain/
│ │ ├── client/
│ │ │ └── PeopleClient.java (Interface)
│ │ ├── entity/
│ │ │ └── People.java
│ │ ├── enums/
│ │ │ └── DataSource.java
│ │ ├── exception/
│ │ │ ├── PeopleException.java
│ │ │ ├── BusinessRuleException.java
│ │ │ ├── ValidationException.java
│ │ │ └── PeopleNotFoundException.java
│ │ └── repository/
│ │ └── PeopleRepository.java (Interface)
│ ├── application/
│ │ ├── dto/
│ │ │ └── PeopleResponse.java
│ │ └── service/
│ │ ├── PeopleService.java (Interface)
│ │ └── PeopleServiceImpl.java
│ └── infrastructure/
│ ├── entrypoint/
│ │ └── grpc/
│ │ └── PeopleServiceGrpcImpl.java
│ ├── client/
│ │ ├── typicode/
│ │ │ ├── TypiCodeClientImpl.java
│ │ │ ├── TypiCodeResponse.java
│ │ │ └── TypiCodeMapper.java (MapStruct)
│ │ └── dummy/
│ │ ├── DummyClientImpl.java
│ │ ├── DummyResponse.java
│ │ ├── DummyListResponse.java
│ │ └── DummyMapper.java (MapStruct)
│ ├── repository/
│ │ └── PeopleRepositoryImpl.java (Strategy Pattern)
│ ├── exception/
│ │ ├── GlobalGrpcExceptionHandler.java
│ │ ├── ExternalServiceException.java
│ │ └── InternalServerException.java
│ ├── logging/
│ │ ├── Logger.java
│ │ ├── LogContext.java
│ │ ├── RequestContext.java
│ │ └── GrpcLoggingInterceptor.java
│ └── config/
│ ├── RepositoryConfig.java
│ └── client/
│ ├── TypiCodeClientConfig.java
│ └── DummyClientConfig.java
├── src/main/proto/
│ └── person.proto
└── src/main/resources/
└── application.yml
```
### Componentes Principais
#### 1. PeopleServiceGrpcImpl (`infrastructure/entrypoint/grpc/PeopleServiceGrpcImpl.java`)
```java
@GrpcService
@RequiredArgsConstructor // Lombok
public class PeopleServiceGrpcImpl extends ReactorPeopleServiceGrpc.PeopleServiceImplBase {
private final PeopleService peopleService; // Interface!
@Override
public Mono getPeople(Mono request) {
return request
.flatMap(req -> peopleService.getById(req.getId()))
.map(people -> PeopleResponseGrpc.newBuilder()
.setId(people.getId())
.setName(people.getName())
.setEmail(people.getEmail())
.build());
}
@Override
public Mono listPeople(Mono request) {
return request
.flatMapMany(req -> peopleService.listAll())
.map(people -> PeopleResponseGrpc.newBuilder()
.setId(people.getId())
.setName(people.getName())
.setEmail(people.getEmail())
.build())
.collectList()
.map(peopleList -> ListPeopleResponseGrpc.newBuilder()
.addAllPeople(peopleList)
.build());
}
}
```
**Responsabilidades:**
- Expor serviços gRPC reativos
- Receber requisições gRPC do API Service
- Delegar para o serviço de aplicação
- Mapear DTOs para protobuf messages
- **Inversão de Dependência:** Injeta interface `PeopleService`, não implementação
#### 2. PeopleService (`application/service/`)
**PeopleService (Interface)**
```java
public interface PeopleService {
Mono getById(Integer id);
Flux listAll();
}
```
**PeopleServiceImpl**
```java
@Service
@RequiredArgsConstructor // Lombok
public class PeopleServiceImpl implements PeopleService {
private final PeopleRepository peopleRepository;
@Override
public Mono getById(Integer id) {
return peopleRepository.findById(id);
}
@Override
public Flux listAll() {
return peopleRepository.findAll();
}
}
```
**Responsabilidades:**
- Orquestrar a lógica de negócio
- Delegar para o repositório
- Camada de abstração entre gRPC service e infraestrutura
#### 3. PeopleRepositoryImpl (`infrastructure/repository/PeopleRepositoryImpl.java`)
```java
@RequiredArgsConstructor // Lombok
public class PeopleRepositoryImpl implements PeopleRepository {
private final Map clientStrategies;
private final DataSource activeDataSource;
@Override
public Mono findById(Integer id) {
return getActiveClient().getPeopleById(id);
}
@Override
public Flux findAll() {
return getActiveClient().listPeople();
}
private PeopleClient getActiveClient() {
return clientStrategies.get(activeDataSource);
}
}
```
**Responsabilidades:**
- Implementar o padrão **Strategy** para seleção dinâmica de fonte de dados
- Gerenciar múltiplas implementações de PeopleClient (TypiCode, Dummy)
- Rotear requisições para a API externa configurada via `client.active-datasource`
- Abstrair a complexidade de múltiplas APIs para o serviço
**Configuração (RepositoryConfig.java):**
```java
@Configuration
public class RepositoryConfig {
@Bean
public PeopleRepository peopleRepository(
TypiCodeClientImpl typiCodeClient,
DummyClientImpl dummyClient,
@Value("${client.active-datasource:TYPICODE}") String activeDataSourceStr) {
Map clientStrategies = new HashMap<>();
clientStrategies.put(DataSource.TYPICODE, typiCodeClient);
clientStrategies.put(DataSource.DUMMY, dummyClient);
DataSource activeDataSource = DataSource.valueOf(activeDataSourceStr.toUpperCase());
return new PeopleRepositoryImpl(clientStrategies, activeDataSource);
}
}
```
A fonte de dados ativa é configurada no `application.yml`:
```yaml
client:
active-datasource: DUMMY # ou TYPICODE
```
#### 4. TypiCodeClientImpl (`infrastructure/client/typicode/TypiCodeClientImpl.java`)
```java
@Component
@RequiredArgsConstructor // Lombok
public class TypiCodeClientImpl implements PeopleClient {
@Qualifier("typiCodeWebClient")
private final WebClient typiCodeWebClient;
private final TypiCodeMapper mapper; // MapStruct
@Override
public Mono getPeopleById(Integer id) {
return typiCodeWebClient
.get()
.uri("/users/{id}", id)
.retrieve()
.bodyToMono(TypiCodeResponse.class)
.map(mapper::toPeopleResponse); // MapStruct
}
@Override
public Flux listPeople() {
return typiCodeWebClient
.get()
.uri("/users")
.retrieve()
.bodyToFlux(TypiCodeResponse.class)
.map(mapper::toPeopleResponse); // MapStruct
}
}
```
**Responsabilidades:**
- Implementar a interface PeopleClient para JSONPlaceholder API
- Realizar chamadas HTTP reativas para `https://jsonplaceholder.typicode.com`
- Mapear respostas JSON para DTOs usando **MapStruct**
- Tratamento de erros reativo
**API Externa:** [JSONPlaceholder](https://jsonplaceholder.typicode.com/)
#### 5. TypiCodeMapper (`infrastructure/client/typicode/TypiCodeMapper.java`)
```java
@Mapper(
componentModel = "spring",
implementationName = "TypiCodeMapperImpl"
)
public interface TypiCodeMapper {
@Mapping(target = "id", source = "id")
@Mapping(target = "name", source = "name")
@Mapping(target = "email", source = "email")
PeopleResponse toPeopleResponse(TypiCodeResponse response);
}
```
**Responsabilidades:**
- Mapeamento **type-safe** de campos da API JSONPlaceholder
- Geração de código em tempo de compilação via MapStruct
#### 6. DummyClientImpl (`infrastructure/client/dummy/DummyClientImpl.java`)
```java
@Component
@RequiredArgsConstructor // Lombok
public class DummyClientImpl implements PeopleClient {
@Qualifier("dummyWebClient")
private final WebClient dummyWebClient;
private final DummyMapper mapper; // MapStruct
@Override
public Mono getPeopleById(Integer id) {
return dummyWebClient
.get()
.uri("/users/{id}", id)
.retrieve()
.bodyToMono(DummyResponse.class)
.map(mapper::toPeopleResponse); // MapStruct
}
@Override
public Flux listPeople() {
return dummyWebClient
.get()
.uri("/users")
.retrieve()
.bodyToMono(DummyListResponse.class)
.flatMapMany(response -> Flux.fromIterable(response.users()))
.map(mapper::toPeopleResponse); // MapStruct
}
}
```
**Responsabilidades:**
- Implementar a interface PeopleClient para DummyJSON API
- Realizar chamadas HTTP reativas para `https://dummyjson.com`
- Mapear respostas JSON para DTOs usando **MapStruct**
- Combinar firstName e lastName em um único campo name via MapStruct
- Tratamento de erros reativo
**API Externa:** [DummyJSON](https://dummyjson.com/)
#### 7. DummyMapper (`infrastructure/client/dummy/DummyMapper.java`)
```java
@Mapper(
componentModel = "spring",
implementationName = "DummyMapperImpl"
)
public interface DummyMapper {
@Mapping(target = "name",
expression = "java(response.firstName() + \" \" + response.lastName())")
@Mapping(target = "email", source = "email")
@Mapping(target = "id", source = "id")
PeopleResponse toPeopleResponse(DummyResponse response);
}
```
**Responsabilidades:**
- Mapeamento **customizado** da API DummyJSON
- Combinar campos `firstName` e `lastName` em `name` via expressão Java
- Geração de código em tempo de compilação via MapStruct
### Configuração (`application.yml`)
```yaml
spring:
application:
name: people
grpc:
server:
port: 9090
client:
active-datasource: TYPICODE # Options: TYPICODE, DUMMY
typicode:
base-url: https://jsonplaceholder.typicode.com
dummy:
base-url: https://dummyjson.com
```
### APIs Externas Suportadas
O People Service suporta múltiplas APIs externas através do padrão **Strategy**, permitindo trocar facilmente a fonte de dados via configuração.
#### JSONPlaceholder (TYPICODE)
**URL Base:** `https://jsonplaceholder.typicode.com`
**Endpoints utilizados:**
- `GET /users/{id}` - Buscar usuário por ID
- `GET /users` - Listar todos os usuários
**Estrutura de resposta:**
```json
{
"id": 1,
"name": "Leanne Graham",
"email": "Sincere@april.biz",
"username": "Bret",
"address": { ... },
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": { ... }
}
```
**Características:**
- API gratuita e pública para testes
- 10 usuários disponíveis
- Campos diretamente mapeados (id, name, email)
#### DummyJSON (DUMMY)
**URL Base:** `https://dummyjson.com`
**Endpoints utilizados:**
- `GET /users/{id}` - Buscar usuário por ID
- `GET /users` - Listar todos os usuários
**Estrutura de resposta:**
```json
{
"id": 1,
"firstName": "Emily",
"lastName": "Johnson",
"email": "emily.johnson@x.dummyjson.com",
"phone": "+81 965-431-3024",
"username": "emilys",
"birthDate": "1996-5-30",
"image": "https://dummyjson.com/icon/emilys/128",
...
}
```
**Características:**
- API gratuita com dados realistas
- Maior quantidade de usuários disponíveis
- Requer mapeamento customizado (firstName + lastName → name)
#### Seleção de Fonte de Dados
A seleção é feita através da propriedade `client.active-datasource`:
```yaml
# Para usar JSONPlaceholder
client:
active-datasource: TYPICODE
# Para usar DummyJSON
client:
active-datasource: DUMMY
```
O padrão Strategy permite adicionar novas APIs externas facilmente, bastando:
1. Criar uma nova implementação de `PeopleClient`
2. Criar um `Mapper` MapStruct para conversão de respostas
3. Adicionar um novo valor no enum `DataSource`
4. Registrar o client no `RepositoryConfig.java`
5. Configurar a URL base no `application.yml`
---
## Estrutura Maven
O projeto utiliza uma estrutura **Maven Multi-Module** para facilitar o build e o gerenciamento de dependências.
### POM Parent/Aggregator
Na raiz do projeto, existe um `pom.xml` que funciona como **aggregator**, gerenciando os módulos:
```xml
org
bridge
1.0-SNAPSHOT
pom
api
people
```
**Benefícios:**
- **Build unificado**: `mvn clean install` na raiz compila ambos os serviços
- **Gerenciamento centralizado**: Versões e configurações podem ser compartilhadas
- **Ordem de build**: Maven resolve automaticamente a ordem de compilação dos módulos
---
## Configuração e Execução
### Pré-requisitos
- Java 21+
- Maven 3.6+
- Conexão com a internet (para acessar JSONPlaceholder)
### Compilação
Na raiz do projeto:
```bash
# Compilar todos os módulos
mvn clean install
# Ou compilar individualmente
cd people
mvn clean install
cd ../api
mvn clean install
```
### Executar os Serviços
**Importante:** O People Service deve ser iniciado ANTES do API Service.
#### 1. Iniciar o People Service
```bash
cd people
mvn spring-boot:run
```
O serviço estará disponível em:
- gRPC Server: `localhost:9090`
#### 2. Iniciar o API Service
```bash
cd api
mvn spring-boot:run
```
O serviço estará disponível em:
- REST API: `http://localhost:8081`
### Verificar a Saúde dos Serviços
```bash
# Verificar People Service (via API Service)
curl http://localhost:8081/api/peoples/1
# Listar todas as pessoas
curl http://localhost:8081/api/peoples
```
---
## Endpoints Disponíveis
### API Service (REST)
#### GET /api/peoples/{id}
Busca uma pessoa por ID.
**Request:**
```http
GET http://localhost:8081/api/peoples/1
```
**Response:**
```json
{
"id": 1,
"name": "Leanne Graham",
"email": "Sincere@april.biz"
}
```
**Status Codes:**
- `200 OK`: Pessoa encontrada
- `500 Internal Server Error`: Erro ao buscar pessoa
---
#### GET /api/peoples
Lista todas as pessoas.
**Request:**
```http
GET http://localhost:8081/api/peoples
```
**Response:**
```json
[
{
"id": 1,
"name": "Leanne Graham",
"email": "Sincere@april.biz"
},
{
"id": 2,
"name": "Ervin Howell",
"email": "Shanna@melissa.tv"
}
]
```
**Status Codes:**
- `200 OK`: Lista retornada com sucesso
- `500 Internal Server Error`: Erro ao listar pessoas
---
## Tratamento de Erros
### API Service
Erros são propagados do People Service para o API Service e retornados como HTTP 500.
### People Service
O People Service possui um sistema robusto de tratamento de exceções:
**Hierarquia de Exceções:**
```
PeopleException (Base)
├── BusinessRuleException (Regras de negócio)
├── ValidationException (Validações)
└── PeopleNotFoundException (Recurso não encontrado)
Infrastructure Exceptions
├── ExternalServiceException (Erros de serviços externos)
└── InternalServerException (Erros internos do servidor)
```
**GlobalGrpcExceptionHandler:**
- Intercepta todas as exceções dos serviços gRPC
- Converte exceções de domínio em status codes gRPC apropriados
- Adiciona contexto e mensagens de erro estruturadas
- Registra erros no sistema de logging
**Status Codes gRPC Retornados:**
- `NOT_FOUND`: Quando recurso não é encontrado
- `INVALID_ARGUMENT`: Para erros de validação
- `FAILED_PRECONDITION`: Para violações de regras de negócio
- `UNAVAILABLE`: Quando serviços externos estão indisponíveis
- `INTERNAL`: Para erros internos não esperados
---
## Observabilidade
### Logs Importantes
**API Service:**
- Requisições HTTP recebidas
- Chamadas gRPC realizadas
- Erros de comunicação
**People Service:**
- Requisições gRPC recebidas
- Chamadas HTTP para JSONPlaceholder
- Erros de integração
### Logging Estruturado (People Service)
O People Service implementa logging estruturado usando **Logstash Logback Encoder**:
**Componentes:**
- **Logger**: Facade customizado para logging estruturado
- **LogContext**: Contexto de log com dados da requisição
- **RequestContext**: Armazena informações de contexto da requisição
- **GrpcLoggingInterceptor**: Interceptor gRPC para log automático de requisições
**Benefícios:**
- Logs em formato JSON para fácil parsing
- Rastreabilidade de requisições com correlation IDs
- Integração com ferramentas de agregação de logs (ELK Stack, Datadog)
### Monitoramento e Observabilidade
**People Service** possui integração com:
- **Datadog APM**: Trace distribuído e métricas de aplicação
- **Logstash**: Logs estruturados em JSON
- **gRPC Server Reflection**: Introspecção de serviços gRPC
**Ambos os serviços** suportam:
- Spring Boot Actuator (pode ser adicionado)
- Métricas Micrometer
- Health checks
---
## Considerações de Segurança
### Configuração Atual
- **Comunicação gRPC**: PLAINTEXT (sem TLS)
- **Comunicação HTTP**: Sem autenticação
### Recomendações para Produção
1. Habilitar TLS/SSL para gRPC
2. Implementar autenticação/autorização (JWT, OAuth2)
3. Configurar rate limiting
4. Adicionar circuit breakers (Resilience4j)
5. Implementar timeouts apropriados
6. Validar inputs
---
## Próximos Passos
- [ ] Adicionar testes de integração
- [ ] Implementar circuit breaker para chamadas externas
- [ ] Adicionar autenticação e autorização
- [ ] Configurar TLS para gRPC
- [ ] Adicionar métricas e tracing distribuído
- [ ] Implementar cache para reduzir chamadas à API externa
- [ ] Adicionar documentação OpenAPI/Swagger para REST API
- [ ] Configurar Docker e Docker Compose
- [ ] Implementar health checks
---
## Referências
### Frameworks e Tecnologias
- [gRPC Documentation](https://grpc.io/docs/)
- [Protocol Buffers](https://developers.google.com/protocol-buffers)
- [Spring WebFlux](https://docs.spring.io/spring-framework/reference/web/webflux.html)
- [Project Reactor](https://projectreactor.io/docs)
- [MapStruct](https://mapstruct.org/)
### APIs Externas
- [JSONPlaceholder API](https://jsonplaceholder.typicode.com/) - API de teste com dados fake
- [DummyJSON API](https://dummyjson.com/) - API de teste com dados realistas