Episódio 34 - Encadeando chamadas REST sem dor: filtrando resultados dinamicamente
No mundo real, sistemas REST são a espinha dorsal de muitos aplicativos Delphi. A comunicação com servidores envolve sequências de chamadas que, quando mal tratadas, geram esperas bloqueantes, códigos duplicados e erros silenciosos. No episódio de hoje, vamos mostrar como transformar essa dor em algo elegante com TTaskChain e TSafeThread.
Cenário comum:
Imagine que você precise:
- Buscar dados de produtos via REST (GET /produtos)
- Aplicar um filtro local baseado na escolha do usuário
- Exibir esses dados na UI
- Em caso de erro, mostrar uma notificação amigável
- Tudo isso sem travar a interface
Solução ingênua (e perigosa):
Memo1.Lines.Text := RESTClient.Get('...');
Filtrar(Memo1.Lines.Text);
AtualizarUI();
Problemas:
- Bloqueia a UI
- Se a conexão falhar, a aplicação congela
- Erros de rede ou parsing geram exceções não tratadas
Solução com TTaskChain
Vamos fazer da forma correta, segmentando cada etapa:
TaskChain := TTaskChain.Create(False);
TaskChain.AddTask('Buscar Produtos',
procedure(const TaskName: string; OnSuccess: TProc; OnError: TErrorCallback)
begin
TSafeThread.ExecuteThread(
TSafeThreadParams.New
.SetOnExecute(
procedure(Context: TThreadContext)
begin
DadosJSON := RESTClient.Get('https://api.exemplo.com/produtos');
if Assigned(OnSuccess) then
OnSuccess();
end)
.SetOnError(
procedure(const Msg: string)
begin
OnError('Erro ao buscar produtos: ' + Msg);
end)
.SetCompleteWithError(True)
);
end);
TaskChain.AddTask('Filtrar Produtos',
procedure(const TaskName: string; OnSuccess: TProc; OnError: TErrorCallback)
begin
TSafeThread.ExecuteThread(
TSafeThreadParams.New
.SetOnExecute(
procedure(Context: TThreadContext)
begin
DadosFiltrados := FiltrarPorCategoria(DadosJSON, CategoriaEscolhida);
if Assigned(OnSuccess) then
OnSuccess();
end)
.SetOnError(
procedure(const Msg: string)
begin
OnError('Erro ao filtrar: ' + Msg);
end)
);
end);
TaskChain.AddTask('Atualizar UI',
procedure(const TaskName: string; OnSuccess: TProc; OnError: TErrorCallback)
begin
TSafeThread.ExecuteThread(
TSafeThreadParams.New
.SetOnExecute(
procedure(Context: TThreadContext)
begin
TThread.Synchronize(nil,
procedure
begin
ExibirProdutos(DadosFiltrados);
end);
if Assigned(OnSuccess) then
OnSuccess();
end)
);
end);
TaskChain.Start;
Resultado:
- Cada etapa é controlada e segura
- Nenhum travamento de UI
- Filtros são reaproveitáveis
- Erros podem ser tratados individualmente
Esse tipo de estrutura é ideal não apenas para REST, mas para qualquer sequência de operações assíncronas com dependências lógicas entre elas.
No próximo episódio, vamos aplicar esse mesmo modelo para sincronizar dados com um banco SQLite local. Sim, offline também pode ser bonito.