@horizon-apps/integration-toolkit
v1.3.0
Published
Toolkit genérico para integração de APIs e sistemas - Profiling, Downloaders, Converters e Utilities
Maintainers
Readme
@horizon-modules/integration-toolkit
Toolkit genérico para integração de APIs e sistemas. Ferramentas reutilizáveis para profiling de dados, análise de datasets e utilitários de integração.
📦 Instalação
npm install @horizon-modules/integration-toolkit
# ou
pnpm add @horizon-modules/integration-toolkit🛠️ Ferramentas Disponíveis
🚀 BatchApiUploader
Serviço para upload em lote de dados JSON para APIs. Processa arquivos JSON de uma pasta e envia para qualquer endpoint configurado.
🔄 BatchFileConverter
Serviço para conversão em lote de arquivos JSON. Lê arquivos de uma pasta, aplica função de conversão e salva os resultados convertidos em outra pasta.
🎯 ObjectTransformer
Serviço genérico para transformação de objetos JSON baseado em regras declarativas. Permite aplicar transformações complexas através de configurações em vez de código.
✨ Características do BatchFileConverter
- 📁 Processamento em lote: Converte todos os arquivos de uma pasta automaticamente
- 🔄 Função customizável: Aceita qualquer função de conversão TypeScript
- 📊 Relatórios detalhados: Estatísticas de conversão e tratamento de erros
- 🎯 Filtros flexíveis: Filtra arquivos por padrões regex ou string
- ⚙️ Configurável: Prefixos de saída, verbose mode e mais
- 🛡️ Type-safe: Suporte completo a TypeScript com tipagem genérica
🚀 Uso Básico do BatchFileConverter
import { BatchFileConverter } from '@horizon-modules/integration-toolkit'
import { convertJetimobPropertyToHorizon } from './converter'
// Converter dados Jetimob para formato Horizon
const converter = new BatchFileConverter({
inputDir: './data/downloads-do-crm',
outputDir: './data/properties-converted',
converter: convertJetimobPropertyToHorizon,
filePattern: /page-\d+\.json$/,
outputPrefix: 'converted-',
verbose: true
})
const result = await converter.convert()
console.log(`✅ ${result.totalConvertedObjects}/${result.totalInputObjects} objetos convertidos`)
console.log(`📊 Taxa de sucesso: ${result.successRate.toFixed(1)}%`)⚙️ Configuração Avançada do BatchFileConverter
import { BatchFileConverter } from '@horizon-modules/integration-toolkit'
// Converter produtos e-commerce
const converter = new BatchFileConverter({
inputDir: '/data/raw-products',
outputDir: '/data/normalized-products',
converter: (rawProduct) => ({
id: rawProduct.codigo,
name: rawProduct.nome,
price: parseFloat(rawProduct.preco),
category: rawProduct.categoria?.nome || 'Sem categoria'
}),
filePattern: 'product-', // String pattern
outputPrefix: 'normalized-',
verbose: true
})
const result = await converter.convert()
// Resultado detalhado
// {
// success: true,
// totalFiles: 5,
// totalInputObjects: 1000,
// totalConvertedObjects: 985,
// totalErrors: 15,
// successRate: 98.5,
// errors: ['file1.json - Item 5: Missing required field'],
// stats: {}
// }📋 Interface BatchFileConverterConfig
interface BatchFileConverterConfig<TInput = any, TOutput = any> {
inputDir: string // Pasta com arquivos de entrada
outputDir: string // Pasta para arquivos convertidos
converter: (input: TInput) => TOutput // Função de conversão
filePattern?: RegExp | string // Filtro de arquivos (padrão: /\.json$/)
outputPrefix?: string // Prefixo de saída (padrão: 'converted-')
verbose?: boolean // Logs detalhados (padrão: false)
}
interface ConvertResult {
success: boolean // Se a operação foi bem-sucedida
totalFiles: number // Arquivos processados
totalInputObjects: number // Objetos de entrada encontrados
totalConvertedObjects: number // Objetos convertidos com sucesso
totalErrors: number // Total de erros
successRate: number // Taxa de sucesso em %
errors: string[] // Lista de erros detalhados
stats: Record<string, number> // Estatísticas customizadas
}✨ Características do BatchApiUploader
- 📁 Leitura automática: Processa todos os
.jsonde uma pasta - 🌐 HTTP flexível: Suporte a POST/PUT com headers customizáveis
- 📊 Relatórios completos: Estatísticas de sincronização (inseridos/atualizados/erros)
- ⚙️ Configurável: Endpoint, método HTTP, campo de batch, delays
- 🔧 Genérico: Funciona com qualquer tipo de dados (imóveis, produtos, etc.)
- ⏱️ Rate limiting: Delay configurável entre requisições
🚀 Uso Básico do BatchApiUploader
import { BatchApiUploader } from '@horizon-modules/integration-toolkit'
// Upload de dados de uma pasta para API
const result = await BatchApiUploader.syncData({
inputDir: '/data/downloads-do-crm',
endpoint: 'http://localhost:3000/api/property/sync',
batchField: 'properties',
method: 'PUT',
verbose: true
})
console.log(result)
// {
// success: true,
// totalFiles: 5,
// totalObjects: 250,
// totalSynced: 248,
// totalErrors: 2,
// successRate: 99.2,
// errors: ['file1.json: HTTP 400: Bad Request']
// }⚙️ Configuração Avançada do BatchApiUploader
import { BatchApiUploader } from '@horizon-modules/integration-toolkit'
const uploader = new BatchApiUploader({
inputDir: '/integrations/jetimob/__dev__/data/downloads-do-crm',
endpoint: 'https://api.example.com/sync',
method: 'POST',
headers: {
'Authorization': 'Bearer token123',
'Content-Type': 'application/json',
'X-API-Version': '2.0'
},
batchField: 'data', // Campo que vai conter o array
delayMs: 500, // 500ms entre requisições
verbose: true
})
const result = await uploader.upload()🎯 Casos de Uso
// Jetimob CRM → Property API
await BatchApiUploader.syncData({
inputDir: '/integrations/jetimob/__dev__/data/downloads-do-crm',
endpoint: 'http://localhost:3000/api/property/sync',
batchField: 'properties',
method: 'PUT'
})
// E-commerce → Inventory API
await BatchApiUploader.syncData({
inputDir: '/data/products',
endpoint: 'https://inventory.example.com/api/bulk',
batchField: 'products',
method: 'POST',
headers: { 'X-Store-ID': 'store123' }
})
// Logs → Analytics API
await BatchApiUploader.syncData({
inputDir: '/logs/processed',
endpoint: 'https://analytics.example.com/events',
batchField: 'events',
delayMs: 100
})📋 Interface BatchApiUploaderConfig
interface BatchApiUploaderConfig {
inputDir: string // Pasta com arquivos JSON
endpoint: string // URL da API de destino
method?: 'POST' | 'PUT' // Método HTTP (padrão: PUT)
headers?: Record<string, string> // Headers customizados
batchField?: string // Campo do payload (padrão: 'data')
delayMs?: number // Delay entre requisições (padrão: 100ms)
verbose?: boolean // Logs detalhados (padrão: false)
}
interface UploadResult {
success: boolean // Se a operação foi bem-sucedida
totalFiles: number // Total de arquivos processados
totalObjects: number // Total de objetos encontrados
totalSynced: number // Total sincronizado com sucesso
totalErrors: number // Total de erros
successRate: number // Taxa de sucesso em %
errors: string[] // Lista de erros detalhados
}📊 ProfilerService
Serviço genérico para análise e profiling de dados JSON. Analisa estruturas de dados, extrai exemplos de campos e gera relatórios estatísticos.
✨ Características
- 📁 Análise de arquivos: Processa arquivos JSON em diretórios
- 💾 Análise em memória: Trabalha com dados carregados em memória
- 🔍 Profiling profundo: Analisa objetos aninhados e arrays
- 📊 Deduplicação: Remove duplicatas baseado em campo chave
- ⚙️ Configurável: Controle de exemplos por campo
- 📈 Relatórios JSON: Saída em formato JSON estruturado
🔧 JsonToZodGenerator
Gerador automático de schemas Zod a partir de dados JSON. Analisa estruturas de dados e cria validações TypeScript type-safe.
✨ Características
- 🔍 Análise automática: Detecta tipos de dados automaticamente
- 🛡️ Type-safe: Gera schemas Zod com tipagem forte
- 🎯 Configurável: Opções de geração personalizáveis
- 📝 Documentação: Adiciona comentários aos schemas gerados
- 🔄 Reutilizável: Detecta e reutiliza interfaces comuns
🚀 Uso Básico
import { JsonToZodGenerator } from '@horizon-modules/integration-toolkit'
const generator = new JsonToZodGenerator({
outputPath: './src/schemas/generated.ts',
interfaceName: 'UserData'
})
const userData = {
id: 1,
name: 'João',
email: '[email protected]',
profile: {
age: 30,
city: 'São Paulo'
}
}
await generator.generateFromData(userData)
// Gera arquivo com:
// export const UserDataSchema = z.object({
// id: z.number(),
// name: z.string(),
// email: z.string().email(),
// profile: z.object({
// age: z.number(),
// city: z.string()
// })
// })🚀 Uso do ProfilerService
import { ProfilerService } from '@horizon-modules/integration-toolkit'
// Análise de arquivos
const profiler = new ProfilerService({
inputDir: './data/json-files',
outputDir: './output',
dataLabel: 'produtos',
serviceLabel: 'API E-commerce'
})
const result = await profiler.profile()
console.log(result)
// {
// "id": [1, 2, 3],
// "name": ["Produto A", "Produto B"],
// "category.name": ["Eletrônicos", "Casa"]
// }💾 Análise em Memória
import { ProfilerService } from '@horizon-modules/integration-toolkit'
// Dados diretos em memória
const data = [
{ id: 1, name: 'João', city: 'São Paulo' },
{ id: 2, name: 'Maria', city: 'Rio de Janeiro' }
]
const profiler = new ProfilerService({
inputData: data,
dataLabel: 'usuários'
})
const result = await profiler.profile()
// Método estático para uso rápido
const quickResult = await ProfilerService.profileData(data, {
defaultMaxExamples: 5
})⚙️ Configuração Avançada
const profiler = new ProfilerService({
inputDir: './data',
outputDir: './reports',
outputFileName: 'custom-profile.json',
verbose: true,
dataLabel: 'imóveis',
serviceLabel: 'CRM Imobiliário',
uniqueField: 'codigo', // Campo para deduplicação
defaultMaxExamples: 20,
fieldConfigs: {
'endereco.cidade': { maxExamples: 50 },
'caracteristicas': { maxExamples: 100 }
}
})
// Análise com deduplicação
const uniqueResult = await profiler.profileUnique()📋 Interface ProfilerConfig
interface ProfilerConfig {
inputDir?: string // Diretório com arquivos JSON
inputData?: any[] // Dados em memória (alternativa)
outputDir?: string // Onde salvar resultado (opcional)
outputFileName?: string // Nome do arquivo de saída
fieldConfigs?: Record<string, FieldConfig> // Config por campo
defaultMaxExamples?: number // Padrão de exemplos (10)
verbose?: boolean // Logs detalhados
uniqueField?: string // Campo para deduplicação
dataLabel?: string // Label dos dados
serviceLabel?: string // Label do serviço
}
interface FieldConfig {
maxExamples?: number // Quantos exemplos guardar
}🎯 Exemplos de Uso
📋 PropertyCustomerRules - Regras de Transformação para Imóveis
Exemplo completo de regras de transformação para padronização de dados imobiliários, localizado em examples/object-transformer/property-customer-rules.ts.
🚀 Uso
import { ObjectTransformer } from '@horizon-integrations/dev-toolkit'
// Copie o arquivo examples/object-transformer/property-customer-rules.ts para seu projeto
import { PropertyCustomerRules } from './path/to/property-customer-rules'
// Usar regras do exemplo para transformação de imóveis
const transformer = new ObjectTransformer({ rules: PropertyCustomerRules })
const propriedade = {
tipo: 'Casa de Condomínio',
vagas: 2,
caracteristicas: ['Sem mobília', 'Churrasqueira'],
corretor_id: 'elvis-ghisi'
}
const transformada = transformer.transform(propriedade)
// Resultado:
// {
// tipo: 'Casa/Sobrado',
// subtipo: 'Casa',
// vagas_garagem: 2,
// caracteristicas: ['Churrasqueira'],
// mobilia: 'Sem mobília',
// tags: ['em-condominio'],
// corretor_slug: 'elvis-ghisi',
// corretor_nome: 'Elvis Ghisi'
// }📋 Transformações Incluídas
🏠 Tipos de Imóveis:
- Residenciais: Apartamento → Apartamento, Casa → Casa/Sobrado, Sobrado → Casa/Sobrado
- Apartamentos: Duplex, Triplex, Cobertura, Loft, Studio, Flat, Garden
- Casas Especiais: Quitinete, Bangalô, Edícula, Chalé, Casa de Condomínio
- Terrenos: Terreno → Terreno/Lote, Lote → Terreno/Lote
- Comerciais: Sala, Loja, Ponto, Conjunto → Comercial (com subtipos)
- Rurais: Fazenda, Sítio, Chácara, Granja → Rural (com tag "rural")
- Industriais: Galpão/Barracão → normalização
🔧 Mapeamentos de Campos:
vagas→vagas_garagem(renomeação)caracteristicas→ processamento de "Sem mobília" → campomobiliacorretor_id→corretor_slug+corretor_nome(exemplo)tags→ mapeamento de agentes para corretores
🎯 Casos de Uso
// Pipeline completo de transformação
import { BatchFileConverter, ObjectTransformer } from '@horizon-integrations/dev-toolkit'
// Copie o arquivo de exemplo para seu projeto
import { PropertyCustomerRules } from './config/property-customer-rules'
const converter = new BatchFileConverter({
inputDir: './data/raw-properties',
outputDir: './data/normalized-properties',
converter: (rawProperty) => {
const transformer = new ObjectTransformer({ rules: PropertyCustomerRules })
return transformer.transform(rawProperty)
},
verbose: true
})
const result = await converter.convert()
console.log(`${result.totalConvertedObjects} imóveis normalizados`)📊 Exemplos Práticos
🔄 Sincronização Jetimob → Property API
import { DataSyncService } from '@horizon-modules/integration-toolkit'
// Sincronizar downloads do CRM Jetimob
const result = await DataSyncService.syncData({
inputDir: '/integrations/jetimob/__dev__/data/downloads-do-crm',
endpoint: 'http://localhost:3000/api/property/sync',
batchField: 'properties',
method: 'PUT',
headers: {
'X-Source': 'jetimob-crm'
},
verbose: true
})
console.log(`✅ ${result.totalSynced}/${result.totalObjects} imóveis sincronizados`)
console.log(`📊 Taxa de sucesso: ${result.successRate}%`)🏠 Análise de Dados Imobiliários
import { ProfilerService } from '@horizon-modules/integration-toolkit'
const profiler = new ProfilerService({
inputDir: './data/imoveis',
outputDir: './profiling',
outputFileName: 'imoveis-profile.json',
dataLabel: 'imóveis',
serviceLabel: 'CRM Jetimob',
uniqueField: 'codigo',
fieldConfigs: {
'endereco_cidade': { maxExamples: 30 },
'tipo': { maxExamples: 10 },
'caracteristicas': { maxExamples: 50 }
}
})
const result = await profiler.profileUnique()
console.log(`Campos analisados: ${Object.keys(result).length}`)📦 Análise de Produtos E-commerce
import { ProfilerService } from '@horizon-modules/integration-toolkit'
const produtos = [
{
id: 1,
nome: 'Smartphone',
categoria: { id: 10, nome: 'Eletrônicos' },
preco: 899.99,
tags: ['oferta', 'destaque']
},
// ... mais produtos
]
const result = await ProfilerService.profileData(produtos, {
dataLabel: 'produtos',
serviceLabel: 'API Loja',
defaultMaxExamples: 15
})
// Resultado:
// {
// "id": [1, 2, 3],
// "nome": ["Smartphone", "Laptop", "Tablet"],
// "categoria.id": [10, 20, 30],
// "categoria.nome": ["Eletrônicos", "Informática"],
// "tags": ["oferta", "destaque", "novo"]
// }📈 Análise de Logs de API
import { ProfilerService } from '@horizon-modules/integration-toolkit'
const profiler = new ProfilerService({
inputDir: './logs/api-calls',
outputDir: './analytics',
dataLabel: 'requisições',
serviceLabel: 'API Gateway',
fieldConfigs: {
'endpoint': { maxExamples: 20 },
'method': { maxExamples: 10 },
'status_code': { maxExamples: 15 }
}
})
const result = await profiler.profile()🎯 ObjectTransformer - Transformação Baseada em Regras
O ObjectTransformer permite transformar objetos JSON através de regras declarativas, eliminando a necessidade de escrever código de transformação customizado para cada caso.
✨ Características
- 🎯 Baseado em regras: Configure transformações via JSON, não código
- 🔄 Transformações complexas: Suporte a condições, arrays, campos aninhados
- 🛡️ Type-safe: Tipagem TypeScript com generics
- 📝 Tags na description: Processa tags especiais em campos de texto
- 🔧 Actions flexíveis: upsertField, removeField, addToArray, removeFromArray
🚀 Uso Básico
import { ObjectTransformer } from '@horizon-modules/integration-toolkit'
// Configurar regras de transformação
const rules = {
fieldRules: [
{
key: 'tipo',
condition: { eq: 'Casa' },
rules: [
{ fn: 'upsertField', key: 'categoria', value: 'Residencial' },
{ fn: 'upsertField', key: 'subtipo', value: 'Casa' }
]
},
{
key: 'caracteristicas',
condition: { has_any: ['Piscina'] },
rules: [
{ fn: 'removeFromArray', key: 'caracteristicas', value: 'Piscina' },
{ fn: 'upsertField', key: 'tem_piscina', value: true }
]
}
]
}
// Criar transformer
const transformer = new ObjectTransformer({ rules })
// Transformar objeto
const propriedade = {
reference: 'PROP001',
tipo: 'Casa',
caracteristicas: ['Piscina', 'Churrasqueira']
}
const transformed = transformer.transform(propriedade)
// Resultado:
// {
// reference: 'PROP001',
// tipo: 'Casa',
// categoria: 'Residencial',
// subtipo: 'Casa',
// caracteristicas: ['Churrasqueira'],
// tem_piscina: true
// }🔄 Combinando com BatchFileConverter
import { BatchFileConverter, ObjectTransformer } from '@horizon-modules/integration-toolkit'
import transformRules from './config/transform-rules'
// Criar transformer com regras
const transformer = new ObjectTransformer({ rules: transformRules })
// Usar com BatchFileConverter
const batchConverter = new BatchFileConverter({
inputDir: './data/input',
outputDir: './data/output',
converter: (obj) => transformer.transform(obj), // Closure com transformer
verbose: true
})
const result = await batchConverter.convert()📋 Condições Suportadas
// Igualdade
condition: { eq: 'Apartamento' }
condition: { not_eq: 'Casa' }
// Arrays
condition: { has: ['churrasqueira'] } // Tem todos os valores
condition: { has_any: ['piscina', 'sauna'] } // Tem qualquer um dos valores
condition: { not_has: ['mobiliado'] } // Não tem o valor
// Numéricos
condition: { gt: 100 } // Maior que
condition: { gte: 100 } // Maior ou igual
condition: { lt: 1000 } // Menor que
condition: { lte: 1000 } // Menor ou igual
// Texto
condition: { contains: 'apartamento' }
condition: { starts_with: 'Casa' }
condition: { ends_with: 'Comercial' }
// Booleanos
condition: { is_true: true }
condition: { is_false: true }
// Existência
condition: { exists: true } // Campo existe
condition: { not_exists: true } // Campo não existe🛠️ Actions Disponíveis
// Criar/atualizar campo
{ fn: 'upsertField', key: 'novo_campo', value: 'valor' }
// Remover campo
{ fn: 'removeField', key: 'campo_antigo' }
// Adicionar valores a array
{ fn: 'addToArray', key: 'tags', value: ['nova-tag'] }
// Remover valores de array
{ fn: 'removeFromArray', key: 'caracteristicas', value: 'Sem mobília' }📝 Processamento de Tags na Description
O ObjectTransformer processa automaticamente tags especiais em campos de texto:
const objeto = {
description: `Casa linda [[description-en]]Beautiful house[[/description-en]]
[[custom-attributes]]
{
"energia_solar": true,
"classificacao": "A+"
}
[[/custom-attributes]]
Com vista para o mar`
}
const transformer = new ObjectTransformer({
rules: {},
processDescriptionTags: true // Padrão: true
})
const resultado = transformer.transform(objeto)
// Resultado:
// {
// description: 'Casa linda Com vista para o mar',
// description_en: 'Beautiful house',
// energia_solar: true,
// classificacao: 'A+'
// }⚙️ Interface Completa
interface TransformRules<T = any> {
referenceRules?: Record<string, TransformAction[]> // Regras por reference
fieldRules?: FieldRule<T>[] // Regras por field
}
interface FieldRule<T = any> {
key: keyof T | string // Campo a verificar
condition?: Record<string, any> // Condição para aplicar regras
rules: TransformAction[] // Actions a executar
}
interface TransformAction {
fn: 'upsertField' | 'removeField' | 'addToArray' | 'removeFromArray'
key: string // Campo alvo da action
value?: any // Valor para a action
type?: string // Tipo do campo (informativo)
label?: string // Label do campo (informativo)
}🧪 Testes
# Executar testes
npm run test
# Testes com cobertura
npm run test:coverage
# Verificar tipos
npm run typecheck🔧 Build
# Build para produção
npm run build
# Build com watch
npm run dev📈 Roadmap
- ✅ DataSyncService: Sincronização genérica de dados JSON com APIs
- ✅ ProfilerService: Profiling e análise de estruturas de dados
- ✅ JsonToZodGenerator: Geração automática de schemas Zod
- BaseDownloader: Classe base para downloaders de API
- BaseConverter: Utilitários para conversão de dados
- ApiClient: Cliente HTTP genérico com retry e rate limiting
- DataTransformer: Transformações de dados baseadas em regras
- ValidationUtils: Utilitários de validação genéricos
📄 Licença
MIT - veja LICENSE para detalhes.
Desenvolvido pela Horizon Modules 🏗️
