testes/Modulos Angular/projects/idt_app/docs/API_INTEGRATION_GUIDE.md

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:

  1. Acessar o Swagger da API: https://prafrota-be-bff-tenant-api.grupopra.tech/swagger#/
  2. Identificar endpoints do domínio desejado
  3. Analisar schemas de request/response
  4. 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

  1. Localizar schema no Swagger (seção "Schemas" ou "Definitions")
  2. Mapear tipos do OpenAPI para TypeScript:
    • stringstring
    • integernumber
    • booleanboolean
    • arrayArray<T>
    • objectinterface
  3. Considerar campos opcionais (marked as required: false)
  4. 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

  1. SEMPRE consultar o Swagger primeiro
  2. Verificar endpoints disponíveis
  3. Analisar schema de dados
  4. Identificar campos obrigatórios vs opcionais
  5. Verificar relacionamentos entre entidades

Durante a Implementação

  1. Usar nomes consistentes com a API
  2. Mapear todos os campos do schema
  3. Incluir validações baseadas na API
  4. Testar endpoints antes de finalizar
  5. Documentar diferenças se houver

Validação da Implementação

  1. Listar entidades funciona
  2. Criar nova entidade funciona
  3. Editar entidade funciona
  4. Excluir entidade funciona
  5. 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 - Sucesso
  • 201 Created - Criado com sucesso
  • 400 Bad Request - Dados inválidos
  • 401 Unauthorized - Não autenticado
  • 403 Forbidden - Sem permissão
  • 404 Not Found - Recurso não encontrado
  • 409 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.';
  }
}


💡 Dica para o MCP: Sempre começar pela consulta ao Swagger para garantir implementação correta e consistente com a API PraFrota!