10 KiB
10 KiB
🌐 Guia de Integração com API PraFrota
📋 Informações da API
URL Base: https://prafrota-be-bff-tenant-api.grupopra.tech
Swagger UI: https://prafrota-be-bff-tenant-api.grupopra.tech/swagger#/
Projeto: PraFrota - Sistema de Gestão de Frota
Empresa: Grupo PRA
🎯 Fluxo MCP para Novos Domínios
Passo 1: Consulta ao Swagger
Quando o MCP precisar implementar um novo domínio:
- Acessar o Swagger da API: https://prafrota-be-bff-tenant-api.grupopra.tech/swagger#/
- Identificar endpoints do domínio desejado
- Analisar schemas de request/response
- Mapear operações CRUD disponíveis
Passo 2: Mapeamento de Endpoints
Padrão Esperado de Endpoints
GET /api/{domain} # Listagem com paginação
POST /api/{domain} # Criação de nova entidade
GET /api/{domain}/{id} # Detalhes de uma entidade
PUT /api/{domain}/{id} # Atualização completa
PATCH /api/{domain}/{id} # Atualização parcial
DELETE /api/{domain}/{id} # Exclusão
Exemplos de Domínios Esperados
/api/vehicles- Gestão de veículos/api/drivers- Gestão de motoristas/api/routes- Gestão de rotas/api/clients- Gestão de clientes/api/companies- Gestão de empresas/api/contracts- Gestão de contratos
Passo 3: Implementação do Service
Template Base para Services
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { DomainService } from '../base-domain/base-domain.component';
@Injectable()
export class {Domain}Service implements DomainService<{Entity}> {
private readonly apiUrl = 'https://prafrota-be-bff-tenant-api.grupopra.tech/api';
private readonly endpoint = '{domain}'; // ex: 'vehicles'
constructor(private http: HttpClient) {}
// ✅ Método obrigatório para BaseDomainComponent
getEntities(page: number, pageSize: number, filters: any): Observable<{
data: {Entity}[];
totalCount: number;
pageCount: number;
currentPage: number;
}> {
const params = new HttpParams()
.set('page', page.toString())
.set('pageSize', pageSize.toString());
// Adicionar filtros se disponíveis na API
Object.keys(filters).forEach(key => {
if (filters[key] !== null && filters[key] !== '') {
params = params.set(key, filters[key]);
}
});
return this.http.get<any>(`${this.apiUrl}/${this.endpoint}`, { params });
}
// ✅ Métodos CRUD para salvamento genérico
create(entity: Partial<{Entity}>): Observable<{Entity}> {
return this.http.post<{Entity}>(`${this.apiUrl}/${this.endpoint}`, entity);
}
update(id: any, entity: Partial<{Entity}>): Observable<{Entity}> {
return this.http.put<{Entity}>(`${this.apiUrl}/${this.endpoint}/${id}`, entity);
}
delete(id: any): Observable<void> {
return this.http.delete<void>(`${this.apiUrl}/${this.endpoint}/${id}`);
}
getById(id: any): Observable<{Entity}> {
return this.http.get<{Entity}>(`${this.apiUrl}/${this.endpoint}/${id}`);
}
// Métodos adicionais específicos do domínio conforme Swagger
}
Passo 4: Schema para Interface TypeScript
Processo de Mapeamento
- Localizar schema no Swagger (seção "Schemas" ou "Definitions")
- Mapear tipos do OpenAPI para TypeScript:
string→stringinteger→numberboolean→booleanarray→Array<T>object→interface
- Considerar campos opcionais (marked as required: false)
- Incluir enums se definidos na API
Template Base para Interfaces
// {entity}.interface.ts
// ✅ Baseado no schema do Swagger da API PraFrota
export interface {Entity} {
// Campos obrigatórios (required: true no schema)
id: string;
name: string;
createdAt: string;
updatedAt: string;
// Campos opcionais (required: false ou não listados)
description?: string;
status?: EntityStatus;
// Relacionamentos
{relation}Id?: string;
{relation}?: {RelatedEntity};
}
export enum EntityStatus {
ACTIVE = 'ACTIVE',
INACTIVE = 'INACTIVE',
PENDING = 'PENDING'
}
// Types auxiliares se necessário
export type {Entity}CreateRequest = Omit<{Entity}, 'id' | 'createdAt' | 'updatedAt'>;
export type {Entity}UpdateRequest = Partial<{Entity}CreateRequest>;
Passo 5: Configuração de Colunas
Mapeamento de Campos para Tabela
// Baseado nos campos do schema da API
protected getDomainConfig(): DomainConfig {
return {
domain: '{domain}',
title: '{Plural}',
entityName: '{singular}',
subTabs: ['dados', 'endereco', 'documentos'], // Conforme necessário
columns: [
// ✅ Campos principais para listagem
{ field: 'id', header: 'ID', sortable: true, visible: false },
{ field: 'name', header: 'Nome', sortable: true, filterable: true },
{ field: 'status', header: 'Status', filterable: true },
{ field: 'createdAt', header: 'Criado em', sortable: true, type: 'date' },
// Campos específicos do domínio baseados no schema
{ field: '{specific_field}', header: '{Header}', sortable: true }
]
};
}
🔧 Orientações Específicas para o MCP
Antes de Implementar um Domínio
- ✅ SEMPRE consultar o Swagger primeiro
- ✅ Verificar endpoints disponíveis
- ✅ Analisar schema de dados
- ✅ Identificar campos obrigatórios vs opcionais
- ✅ Verificar relacionamentos entre entidades
Durante a Implementação
- ✅ Usar nomes consistentes com a API
- ✅ Mapear todos os campos do schema
- ✅ Incluir validações baseadas na API
- ✅ Testar endpoints antes de finalizar
- ✅ Documentar diferenças se houver
Validação da Implementação
- ✅ Listar entidades funciona
- ✅ Criar nova entidade funciona
- ✅ Editar entidade funciona
- ✅ Excluir entidade funciona
- ✅ Filtros e ordenação funcionam
🎮 Exemplo Completo: Veículos
1. Endpoints Identificados no Swagger
GET /api/vehicles # Listagem de veículos
POST /api/vehicles # Criar veículo
GET /api/vehicles/{id} # Detalhes do veículo
PUT /api/vehicles/{id} # Atualizar veículo
DELETE /api/vehicles/{id} # Excluir veículo
2. Schema Extraído
{
"Vehicle": {
"type": "object",
"required": ["plate", "model", "year"],
"properties": {
"id": { "type": "string" },
"plate": { "type": "string" },
"model": { "type": "string" },
"year": { "type": "integer" },
"status": { "type": "string", "enum": ["ACTIVE", "INACTIVE", "MAINTENANCE", "RENTED", "STOLEN", "CRASHED", "FOR_SALE", "SCRAPPED", "RESERVED", "UNDER_REPAIR"] },
"brand": { "type": "string" },
"color": { "type": "string" }
}
}
}
3. Interface TypeScript
export interface Vehicle {
id: string;
plate: string; // obrigatório
model: string; // obrigatório
year: number; // obrigatório
status?: VehicleStatus;
brand?: string;
color?: string;
createdAt?: string;
updatedAt?: string;
}
export enum VehicleStatus {
ACTIVE = 'ACTIVE', // ✅ Ativo na frota
INACTIVE = 'INACTIVE', // ❌ Inativo
MAINTENANCE = 'MAINTENANCE', // 🔧 Em manutenção
RENTED = 'RENTED', // 🏠 Alugado
STOLEN = 'STOLEN', // 🚨 Roubado
CRASHED = 'CRASHED', // 💥 Sinistrado
FOR_SALE = 'FOR_SALE', // 💰 Em venda
SCRAPPED = 'SCRAPPED', // ♻️ Sucateado
RESERVED = 'RESERVED', // 📋 Reservado
UNDER_REPAIR = 'UNDER_REPAIR' // 🔨 Em reparo
}
4. Service Implementado
@Injectable()
export class VehiclesService implements DomainService<Vehicle> {
private readonly apiUrl = 'https://prafrota-be-bff-tenant-api.grupopra.tech/api';
// ... implementação conforme template
}
5. Component Final
export class VehiclesComponent extends BaseDomainComponent<Vehicle> {
protected getDomainConfig(): DomainConfig {
return {
domain: 'vehicle',
title: 'Veículos',
entityName: 'veículo',
subTabs: ['dados', 'documentos', 'manutencao'],
columns: [
{ field: 'plate', header: 'Placa', sortable: true, filterable: true },
{ field: 'model', header: 'Modelo', sortable: true, filterable: true },
{ field: 'year', header: 'Ano', sortable: true },
{ field: 'status', header: 'Status', filterable: true },
{ field: 'brand', header: 'Marca', sortable: true }
]
};
}
}
🚨 Tratamento de Erros da API
Códigos de Status Esperados
200 OK- Sucesso201 Created- Criado com sucesso400 Bad Request- Dados inválidos401 Unauthorized- Não autenticado403 Forbidden- Sem permissão404 Not Found- Recurso não encontrado409 Conflict- Conflito (ex: duplicata)500 Internal Server Error- Erro do servidor
Implementação de Error Handling
import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';
// No service
create(entity: Partial<Vehicle>): Observable<Vehicle> {
return this.http.post<Vehicle>(`${this.apiUrl}/vehicles`, entity)
.pipe(
catchError(error => {
console.error('Erro ao criar veículo:', error);
// Transformar erro da API em mensagem amigável
return throwError(() => this.handleApiError(error));
})
);
}
private handleApiError(error: any): string {
switch (error.status) {
case 400: return 'Dados inválidos. Verifique os campos obrigatórios.';
case 409: return 'Já existe um veículo com esta placa.';
default: return 'Erro interno. Tente novamente.';
}
}
🔗 Links Úteis
- Swagger da API: https://prafrota-be-bff-tenant-api.grupopra.tech/swagger#/
- Documentação do Framework: ../src/app/shared/components/tab-system/README.md
- Base Domain Component: ../src/app/shared/components/base-domain/base-domain.component.ts
💡 Dica para o MCP: Sempre começar pela consulta ao Swagger para garantir implementação correta e consistente com a API PraFrota!