Desenvolver aplicações que consomem dados externos é uma rotina comum para o desenvolvedor backend.
Nesta masterclass, vamos criar um sistema de monitoramento de ativos financeiros.
Imagine que precisamos rastrear papéis do mercado acionário brasileiro em tempo real, fornecendo cotações atualizadas para os usuários do seu portal.
Se fizermos uma requisição HTTP para a API da bolsa a cada visita do usuário, nosso servidor irá colapsar por exaustão de conexões.
Além disso, a API de origem fatalmente bloqueará nosso IP por excesso de requisições, o famoso “Rate Limit Exceeded”.
A solução arquitetural correta é implementar uma camada de Service Layer com cache estratégico no banco de dados MySQL.
Isso protege a nossa infraestrutura, economiza banda e garante respostas em questão de milissegundos para o front-end.
Vamos explorar como construir isso de forma robusta e orientada a objetos, isolando a lógica de negócio das funções do WordPress.
A Estrutura do Banco de Dados para Cache
O primeiro passo é projetar a tabela que servirá como nosso repositório de cotações em cache.
Não utilizaremos a tabela wp_options, pois ela é carregada integralmente na memória a cada boot do WordPress, o que destruiria a performance do site se tivéssemos milhares de ativos.
Criaremos uma tabela customizada chamada carteira_cotacoes_cache.
Esta tabela possuirá o ticker do ativo como chave primária (exemplo: PETR4 ou VALE3), o valor atual, a variação percentual e a data da última atualização.
A escolha do tipo de dado DECIMAL para valores financeiros é inegociável, pois o tipo FLOAT causa erros de arredondamento em cálculos matemáticos precisos.
Adicionaremos também um índice na coluna de data de atualização para facilitar a rotina de limpeza de dados obsoletos (Garbage Collection).
A estruturação correta da base de dados é o que diferencia um sistema amador de uma plataforma escalável de nível corporativo.
CREATE TABLE carteira_cotacoes_cache (
ticker VARCHAR(10) NOT NULL,
preco_atual DECIMAL(10, 2) NOT NULL,
variacao_dia DECIMAL(5, 2) NOT NULL,
volume_negociado BIGINT UNSIGNED,
atualizado_em DATETIME NOT NULL,
payload_raw JSON,
PRIMARY KEY (ticker),
INDEX idx_atualizacao (atualizado_em)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
Isolamento com Interfaces (SOLID)
Antes de escrevermos a requisição cURL, precisamos definir um contrato formal usando Interfaces do PHP.
O Princípio da Inversão de Dependência (o “D” do SOLID) nos ensina que módulos de alto nível não devem depender de módulos de baixo nível.
Se amanhã a API financeira que utilizamos mudar suas rotas ou quebrar, ou se decidirmos trocar de provedor de dados, nosso sistema não deve precisar de refatoração profunda.
Criaremos a interface CotacaoProviderInterface.
Qualquer classe que se proponha a buscar dados da bolsa de valores deverá implementar os métodos definidos nesta interface.
Isso facilita imensamente a criação de testes unitários, pois podemos criar uma classe falsa (Mock) que implementa a interface e retorna dados estáticos para validar a lógica do nosso painel, sem consumir créditos da API real durante os testes.
interface CotacaoProviderInterface {
/**
* Busca os dados atualizados de um ativo específico.
*/
public function getDadosAtivo(string $ticker): array;
}
class AlphaVantageProvider implements CotacaoProviderInterface {
private string $api_key;
public function __construct(string $key) {
$this->api_key = $key;
}
public function getDadosAtivo(string $ticker): array {
// Implementação real da requisição HTTP omitida para brevidade
// Retornaria um array com preco_atual, variacao_dia, etc.
return [];
}
}
A Camada de Serviço (Service Layer)
Agora construiremos o “Cérebro” da nossa aplicação, o Service Layer.
Esta classe orquestrará o fluxo de dados entre o banco de dados (nosso cache) e o provedor de dados externo.
Quando o usuário solicitar o preço de um ativo, o serviço primeiro consultará a tabela carteira_cotacoes_cache.
Se o registro existir e tiver sido atualizado há menos de cinco minutos, retornamos o valor em milissegundos.
Se o registro for mais antigo que nossa tolerância, o serviço acionará a interface do provedor para buscar o novo valor.
Após receber a resposta fresca, o serviço executa um comando SQL de UPDATE ou INSERT (Upsert) na nossa tabela.
Para garantir que múltiplas requisições simultâneas não tentem atualizar o mesmo ativo ao mesmo tempo (efeito manada), podemos usar o comando GET_LOCK() do MySQL para enfileirar as execuções.
class MonitorAtivosService {
private CotacaoProviderInterface $provider;
private int $tempo_cache_segundos = 300; // 5 minutos de tolerância
public function __construct(CotacaoProviderInterface $provider) {
$this->provider = $provider;
}
public function obterCotacao(string $ticker): array {
global $wpdb;
$query = $wpdb->prepare(
"SELECT * FROM carteira_cotacoes_cache WHERE ticker = %s",
$ticker
);
$cache = $wpdb->get_row($query, ARRAY_A);
$agora = time();
$precisa_atualizar = true;
if ($cache) {
$ultima_att = strtotime($cache['atualizado_em']);
if (($agora - $ultima_att) < $this->tempo_cache_segundos) {
$precisa_atualizar = false;
}
}
if (!$precisa_atualizar) {
return $cache; // Retorno ultra-rápido do MySQL
}
// Lock preventivo no MySQL para concorrência
$lock_name = "atualiza_ticker_" . $ticker;
$wpdb->query($wpdb->prepare("SELECT GET_LOCK(%s, 5)", $lock_name));
try {
$dados_novos = $this->provider->getDadosAtivo($ticker);
$wpdb->query($wpdb->prepare(
"INSERT INTO carteira_cotacoes_cache
(ticker, preco_atual, variacao_dia, atualizado_em)
VALUES (%s, %f, %f, NOW())
ON DUPLICATE KEY UPDATE
preco_atual = VALUES(preco_atual),
variacao_dia = VALUES(variacao_dia),
atualizado_em = NOW()",
$ticker, $dados_novos['preco_atual'], $dados_novos['variacao_dia']
));
return $dados_novos;
} finally {
// Liberação obrigatória do Lock
$wpdb->query($wpdb->prepare("SELECT RELEASE_LOCK(%s)", $lock_name));
}
}
}
Tratamento de Exceções e Resiliência
O que acontece se a API financeira estiver fora do ar no momento da atualização?
Uma aplicação júnior exibiria um erro fatal para o usuário final, quebrando o layout da página.
Nossa aplicação sênior é desenhada para ser resiliente e tolerante a falhas.
Se a chamada ao provedor falhar (por exemplo, retornando um status HTTP 500), nós capturamos essa exceção no bloco try-catch.
No catch, verificamos se possuímos um cache antigo do ativo (Stale Cache).
Se tivermos, retornamos o preço antigo e inserimos um alerta silencioso no log do servidor informando a degradação do serviço.
Para o investidor que acessa o site, ver uma cotação com 10 minutos de atraso é infinitamente melhor do que ver uma tela de erro em branco.
Alta disponibilidade significa manter o sistema operando, mesmo quando suas dependências externas falham criticamente.
A Criação do Endpoint REST Otimizado
Para disponibilizar esses dados para o nosso front-end (talvez construído em React ou Vue), criaremos um endpoint personalizado na REST API do WordPress.
Utilizaremos a função register_rest_route associada a um método de callback.
No callback, validamos e sanitizamos o parâmetro do ticker usando preg_match para garantir que ele contenha apenas letras e números, mitigando qualquer tentativa de SQL Injection.
Instanciamos nosso provider, injetamos ele no nosso serviço principal e devolvemos a resposta via wp_send_json_success.
Esta separação de camadas permite que a mesma lógica de busca seja usada tanto na API REST quanto em um Shortcode antigo do PHP, provando a versatilidade do Clean Code.
Segurança e Ocultação de Chaves de API
Um erro primário de segurança é inserir as chaves de API diretamente no código-fonte (Hardcoding).
Se o seu repositório Git vazar, crackers utilizarão sua chave financeira para realizar milhões de requisições, gerando um prejuízo enorme.
No ecossistema WordPress, a prática sênior dita que essas chaves devem ser salvas na tabela wp_options, acessíveis via get_option(), ou melhor ainda, declaradas como constantes no arquivo wp-config.php.
Ao usar o wp-config.php, a chave reside apenas no ambiente do servidor de produção, totalmente invisível para o controle de versão do Git.
A injeção de dependência na inicialização da classe garante que a chave flua de forma segura até o componente que realiza a chamada HTTP.
Conclusão da Arquitetura
Esta aplicação demonstra a fundação do desenvolvimento backend maduro.
Integramos concorrência segura com locks do banco, cache de alta performance, injeção de dependências e tratamento de falhas em degradação graciosa.
Esta mesma arquitetura pode ser adaptada para buscar a previsão do tempo, calcular fretes de transportadoras ou integrar sistemas de inteligência artificial.
O domínio da lógica é flexível; o rigor da engenharia é permanente.
Continue elevando o padrão do código que você produz e suas aplicações WordPress nunca mais sofrerão com lentidão ou instabilidade.


