# Exemplos Práticos de Uso da API - OllaHubBackend Este documento contém exemplos práticos e casos de uso comuns para integração com a API do OllaHubBackend. --- ## Configuração Inicial ### TypeScript/JavaScript - Cliente Base ```typescript // api-client.ts const API_BASE_URL = 'http://127.0.0.1:8080'; const WS_BASE_URL = 'ws://127.0.0.1:8080'; class OllaHubClient { private token: string | null = null; constructor(token?: string) { this.token = token || null; } setToken(token: string) { this.token = token; } private async request( endpoint: string, options: RequestInit = {} ): Promise { const headers: HeadersInit = { 'Content-Type': 'application/json', ...options.headers, }; if (this.token) { headers['Authorization'] = `Bearer ${this.token}`; } const response = await fetch(`${API_BASE_URL}${endpoint}`, { ...options, headers, }); if (!response.ok) { const error = await response.json(); throw new Error(error.error || `HTTP ${response.status}`); } if (response.status === 204) { return null as T; } return response.json(); } // Health async health(): Promise<{ status: string }> { return this.request('/v2/health'); } // Modelos async listModels(): Promise> { return this.request('/v2/api/models'); } async installModel(name: string): Promise<{ status: string; model: string }> { return this.request('/v2/api/models/install', { method: 'POST', body: JSON.stringify({ name }), }); } // Criptografia async setCryptoKey(hexKey: string): Promise<{ ok: boolean }> { return this.request('/v2/api/crypto/set-key', { method: 'POST', body: JSON.stringify({ hex_key: hexKey }), }); } async rotateCryptoKey(): Promise<{ key: string }> { return this.request('/v2/api/crypto/rotate-key', { method: 'POST', }); } async encrypt(data: string): Promise<{ ciphertext: string }> { return this.request('/v2/api/crypto/encrypt', { method: 'POST', body: JSON.stringify({ data }), }); } async decrypt(ciphertext: string): Promise<{ plaintext: string }> { return this.request('/v2/api/crypto/decrypt', { method: 'POST', body: JSON.stringify({ data: ciphertext }), }); } // Usuários async listUsers(): Promise> { return this.request('/api/v1/users'); } async getUser(id: string): Promise<{ id: string; name: string; email: string }> { return this.request(`/api/v1/users/${id}`); } async createUser(data: { name: string; email: string }): Promise<{ id: string; name: string; email: string }> { return this.request('/api/v1/users', { method: 'POST', body: JSON.stringify(data), }); } async updateUser(id: string, data: { name?: string; email?: string }): Promise<{ id: string; name: string; email: string }> { return this.request(`/api/v1/users/${id}`, { method: 'PUT', body: JSON.stringify(data), }); } async deleteUser(id: string): Promise { return this.request(`/api/v1/users/${id}`, { method: 'DELETE', }); } // WebSocket createWebSocket(): WebSocket { return new WebSocket(`${WS_BASE_URL}/v2/ws`); } } export default OllaHubClient; ``` --- ## Casos de Uso ### 1. Verificar Status do Sistema ```typescript import OllaHubClient from './api-client'; const client = new OllaHubClient(); async function checkSystem() { try { const health = await client.health(); console.log('Sistema OK:', health); } catch (error) { console.error('Sistema indisponível:', error); } } checkSystem(); ``` --- ### 2. Verificar e Instalar Ollama ```typescript async function checkAndInstallOllama() { try { // Verificar status const response = await fetch('http://127.0.0.1:8080/ollama/install-check'); const status = await response.json(); console.log('Status Ollama:', { instalado: status.installed, rodando: status.service_running, api: status.api_status, }); if (!status.installed || status.api_status !== 'reachable') { console.log('Iniciando instalação...'); const installResponse = await fetch('http://127.0.0.1:8080/ollama/install', { method: 'POST', }); const installResult = await installResponse.json(); if (installResult.installed && installResult.service_started) { console.log('Ollama instalado e rodando!'); } else { console.error('Falha na instalação:', installResult.issues); if (installResult.manual_instructions) { console.log('Instruções manuais:', installResult.manual_instructions); } } } } catch (error) { console.error('Erro:', error); } } checkAndInstallOllama(); ``` --- ### 3. Listar e Instalar Modelos com Progresso ```typescript import OllaHubClient from './api-client'; const client = new OllaHubClient('seu_token_jwt'); async function installModelWithProgress(modelName: string) { return new Promise((resolve, reject) => { // 1. Conectar WebSocket const ws = client.createWebSocket(); let modelInstalled = false; ws.onopen = async () => { console.log('WebSocket conectado'); // 2. Iniciar instalação try { await client.installModel(modelName); console.log(`Instalação de ${modelName} iniciada`); } catch (error) { console.error('Erro ao iniciar instalação:', error); ws.close(); reject(error); } }; ws.onmessage = (event) => { const data = JSON.parse(event.data); switch (data.kind) { case 'Log': console.log('📝', data.message); break; case 'Progress': try { const progress = JSON.parse(data.message); console.log('📊 Progresso:', progress); } catch { console.log('📊', data.message); } break; case 'Done': console.log('✅', data.message); modelInstalled = true; ws.close(); resolve(); break; case 'Error': console.error('❌ Erro:', data.message); ws.close(); reject(new Error(data.message)); break; } }; ws.onerror = (error) => { console.error('Erro WebSocket:', error); reject(error); }; ws.onclose = () => { if (!modelInstalled) { reject(new Error('Conexão WebSocket fechada antes da conclusão')); } }; }); } // Uso async function main() { try { // Listar modelos disponíveis const models = await client.listModels(); console.log('Modelos disponíveis:', models); // Instalar um modelo await installModelWithProgress('llama2:7b'); console.log('Modelo instalado com sucesso!'); } catch (error) { console.error('Erro:', error); } } main(); ``` --- ### 4. Sistema de Criptografia Completo ```typescript import OllaHubClient from './api-client'; const client = new OllaHubClient('seu_token_jwt'); async function cryptoWorkflow() { try { // 1. Gerar nova chave console.log('Gerando nova chave de criptografia...'); const { key } = await client.rotateCryptoKey(); console.log('Chave gerada:', key); // Salvar chave localmente (ex: localStorage, secure storage) localStorage.setItem('crypto_key', key); // 2. Criptografar dados sensíveis const sensitiveData = 'senha_super_secreta_123'; console.log('Criptografando dados...'); const { ciphertext } = await client.encrypt(sensitiveData); console.log('Dados criptografados:', ciphertext); // 3. Descriptografar console.log('Descriptografando...'); const { plaintext } = await client.decrypt(ciphertext); console.log('Dados descriptografados:', plaintext); if (plaintext === sensitiveData) { console.log('✅ Criptografia funcionando corretamente!'); } } catch (error) { console.error('Erro no fluxo de criptografia:', error); } } // Usar chave existente async function useExistingKey() { const savedKey = localStorage.getItem('crypto_key'); if (!savedKey) { console.error('Chave não encontrada'); return; } try { await client.setCryptoKey(savedKey); console.log('Chave configurada com sucesso'); } catch (error) { console.error('Erro ao configurar chave:', error); } } cryptoWorkflow(); ``` --- ### 5. Gerenciamento Completo de Usuários ```typescript import OllaHubClient from './api-client'; const client = new OllaHubClient('seu_token_jwt'); async function userManagementDemo() { try { // 1. Criar usuários console.log('Criando usuários...'); const user1 = await client.createUser({ name: 'João Silva', email: 'joao@example.com', }); console.log('Usuário criado:', user1); const user2 = await client.createUser({ name: 'Maria Santos', email: 'maria@example.com', }); console.log('Usuário criado:', user2); // 2. Listar todos console.log('\nListando usuários...'); const users = await client.listUsers(); console.log('Total de usuários:', users.length); users.forEach(u => console.log(`- ${u.name} (${u.email})`)); // 3. Obter usuário específico console.log('\nObtendo usuário específico...'); const user = await client.getUser(user1.id); console.log('Usuário:', user); // 4. Atualizar usuário console.log('\nAtualizando usuário...'); const updated = await client.updateUser(user1.id, { name: 'João Silva Atualizado', email: 'joao.novo@example.com', }); console.log('Usuário atualizado:', updated); // 5. Deletar usuário console.log('\nDeletando usuário...'); await client.deleteUser(user2.id); console.log('Usuário deletado'); // 6. Verificar lista final const finalUsers = await client.listUsers(); console.log('\nUsuários restantes:', finalUsers.length); } catch (error) { console.error('Erro no gerenciamento de usuários:', error); } } userManagementDemo(); ``` --- ### 6. Tratamento de Erros Robusto ```typescript import OllaHubClient from './api-client'; const client = new OllaHubClient('seu_token_jwt'); async function robustRequest( fn: () => Promise, retries = 3 ): Promise { for (let i = 0; i < retries; i++) { try { return await fn(); } catch (error: any) { const isLastAttempt = i === retries - 1; if (error.message.includes('401')) { throw new Error('Token JWT inválido. Faça login novamente.'); } if (error.message.includes('500')) { if (isLastAttempt) { throw new Error('Erro interno do servidor. Tente novamente mais tarde.'); } console.warn(`Tentativa ${i + 1} falhou, tentando novamente...`); await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); continue; } throw error; } } throw new Error('Número máximo de tentativas excedido'); } // Uso async function exemploComRetry() { try { const models = await robustRequest(() => client.listModels()); console.log('Modelos:', models); } catch (error) { console.error('Erro após retries:', error); } } exemploComRetry(); ``` --- ### 7. Hook React para WebSocket ```typescript // useWebSocket.ts import { useEffect, useState, useRef } from 'react'; interface WsEvent { kind: 'Log' | 'Progress' | 'Done' | 'Error'; message: string; } export function useWebSocket(url: string) { const [events, setEvents] = useState([]); const [connected, setConnected] = useState(false); const wsRef = useRef(null); useEffect(() => { const ws = new WebSocket(url); wsRef.current = ws; ws.onopen = () => { setConnected(true); console.log('WebSocket conectado'); }; ws.onmessage = (event) => { const data: WsEvent = JSON.parse(event.data); setEvents(prev => [...prev, data]); }; ws.onerror = (error) => { console.error('Erro WebSocket:', error); }; ws.onclose = () => { setConnected(false); console.log('WebSocket desconectado'); }; return () => { ws.close(); }; }, [url]); return { events, connected }; } // Uso no componente function ModelInstallation() { const { events, connected } = useWebSocket('ws://127.0.0.1:8080/v2/ws'); const client = new OllaHubClient('token'); const handleInstall = async (modelName: string) => { try { await client.installModel(modelName); } catch (error) { console.error('Erro:', error); } }; return (
Status: {connected ? 'Conectado' : 'Desconectado'}
{events.map((event, i) => (
{event.kind}: {event.message}
))}
); } ``` --- ### 8. Validação de Dados no Frontend ```typescript // validators.ts export function validateEmail(email: string): boolean { const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return re.test(email); } export function validateName(name: string): string | null { if (name.length < 2) { return 'Nome deve ter pelo menos 2 caracteres'; } return null; } export function validateCryptoKey(hexKey: string): string | null { if (!/^[0-9a-fA-F]{64}$/.test(hexKey)) { return 'Chave deve ter 64 caracteres hexadecimais (32 bytes)'; } return null; } export function validateModelName(name: string): string | null { if (!/^[a-zA-Z0-9:._-]+$/.test(name)) { return 'Nome do modelo contém caracteres inválidos'; } return null; } // Uso async function createUserWithValidation(data: { name: string; email: string }) { const nameError = validateName(data.name); if (nameError) { throw new Error(nameError); } if (!validateEmail(data.email)) { throw new Error('Email inválido'); } return client.createUser(data); } ``` --- ### 9. Cache de Modelos ```typescript // model-cache.ts class ModelCache { private cache: Array<{ name: string; description?: string }> | null = null; private cacheTime: number = 0; private readonly TTL = 5 * 60 * 1000; // 5 minutos async getModels(client: OllaHubClient, forceRefresh = false): Promise> { const now = Date.now(); if (!forceRefresh && this.cache && (now - this.cacheTime) < this.TTL) { return this.cache; } try { const models = await client.listModels(); this.cache = models; this.cacheTime = now; return models; } catch (error) { if (this.cache) { console.warn('Erro ao atualizar cache, usando cache antigo:', error); return this.cache; } throw error; } } clear() { this.cache = null; this.cacheTime = 0; } } // Uso const cache = new ModelCache(); const models = await cache.getModels(client); ``` --- ### 10. Monitoramento de Saúde do Sistema ```typescript async function monitorSystemHealth(intervalMs = 30000) { const checkHealth = async () => { try { const health = await client.health(); console.log('✅ Sistema saudável:', new Date().toISOString()); return true; } catch (error) { console.error('❌ Sistema indisponível:', error); return false; } }; // Verificação inicial await checkHealth(); // Verificações periódicas setInterval(checkHealth, intervalMs); } // Monitorar com alertas async function monitorWithAlerts() { let consecutiveFailures = 0; const MAX_FAILURES = 3; setInterval(async () => { const isHealthy = await checkHealth(); if (!isHealthy) { consecutiveFailures++; if (consecutiveFailures >= MAX_FAILURES) { console.error('🚨 ALERTA: Sistema indisponível há múltiplas verificações!'); // Enviar notificação, email, etc. } } else { consecutiveFailures = 0; } }, 30000); } ``` --- ## Casos de Erro Comuns e Soluções ### Erro 401: Unauthorized **Causa**: Token JWT ausente ou inválido. **Solução**: ```typescript try { await client.listModels(); } catch (error: any) { if (error.message.includes('401')) { // Redirecionar para login ou renovar token console.log('Token inválido, faça login novamente'); } } ``` ### Erro 400: Bad Request - Validação **Causa**: Dados de entrada inválidos. **Solução**: ```typescript try { await client.createUser({ name: 'A', email: 'invalid' }); } catch (error: any) { if (error.message.includes('validação')) { console.error('Erro de validação:', error.message); // Mostrar erros específicos ao usuário } } ``` ### Erro 409: Conflict - Chave Já Definida **Causa**: Tentativa de definir chave de criptografia quando já existe. **Solução**: ```typescript try { await client.setCryptoKey(key); } catch (error: any) { if (error.message.includes('já definida')) { console.log('Chave já configurada, usando existente'); // Continuar com operações de criptografia } } ``` ### WebSocket Desconectado **Causa**: Conexão perdida durante operação. **Solução**: ```typescript function createResilientWebSocket(url: string, onReconnect: () => void) { let ws: WebSocket; let reconnectAttempts = 0; const MAX_RECONNECTS = 5; function connect() { ws = new WebSocket(url); ws.onopen = () => { reconnectAttempts = 0; console.log('WebSocket conectado'); }; ws.onclose = () => { if (reconnectAttempts < MAX_RECONNECTS) { reconnectAttempts++; const delay = Math.min(1000 * Math.pow(2, reconnectAttempts), 30000); console.log(`Reconectando em ${delay}ms...`); setTimeout(() => { connect(); onReconnect(); }, delay); } else { console.error('Máximo de tentativas de reconexão atingido'); } }; } connect(); return ws; } ``` --- ## Boas Práticas 1. **Sempre trate erros**: Use try/catch em todas as chamadas de API 2. **Valide dados no frontend**: Reduza requisições inválidas 3. **Use cache quando apropriado**: Reduza carga no servidor 4. **Implemente retry logic**: Para operações críticas 5. **Monitore saúde do sistema**: Detecte problemas cedo 6. **Gerencie tokens JWT**: Renove antes de expirar 7. **Use WebSocket para operações longas**: Melhor UX 8. **Log erros adequadamente**: Facilita debugging --- **Última Atualização**: 2024