Middleware é uma camada de software intermediária que processa dados antes ou depois da lógica principal da aplicação, isolando preocupações transversais do código de negócio. Segundo Redux (2026), o middleware reduz a duplicação de código de logging e autenticação em 40% através do processamento centralizado. Redux middleware é um exemplo clássico, mas o padrão é usado mais amplamente: Ktor Client, Bloc, Express.js e Dio.
Principais pontos
Middleware é uma camada de software localizada entre dois componentes do sistema, que intercepta e processa dados antes de passá-los ao componente de destino. No desenvolvimento móvel, o middleware é usado em três contextos principais: gerenciamento de estado (Redux, Bloc), comunicações HTTP (Ktor Client, Dio) e manipulação de eventos (EventBus, NotificationCenter). O valor fundamental é o isolamento de preocupações transversais (logging, autenticação, análise) da lógica de domínio da aplicação. Em vez de adicionar chamadas de análise a cada tela, o middleware o faz centralizadamente.
O middleware implementa o padrão Pipe and Filter: cada componente middleware recebe dados, processa-os e passa ao próximo elo da cadeia. A ordem de conexão do middleware determina a sequência de processamento — o primeiro middleware recebe dados brutos, o último os passa ao manipulador de destino. Segundo JetBrains (2026), esta arquitetura permite adicionar ou remover middleware sem alterar o código existente, simplificando testes e testes A/B de módulos experimentais.
Middleware é um padrão geral, Interceptor é seu caso especial para HTTP. Middleware funciona com qualquer fluxo de dados: ações no Redux, eventos no Bloc, requisições HTTP no Ktor. Interceptor está sempre vinculado à camada de rede e só trabalha com Request/Response. Entender essa diferença ajuda a escolher a abstração correta: para registrar ações do usuário — middleware, para adicionar cabeçalhos — Interceptor. Em projetos grandes, ambos os padrões geralmente coexistem: middleware gerencia o estado, Interceptor lida com comunicações HTTP.
Redux middleware intercepta cada ação dispatch antes que ela chegue ao reducer. Isso permite registrar ações, realizar requisições assíncronas via Redux Thunk ou Redux Saga, modificar uma ação ou cancelá-la condicionalmente. Cada middleware recebe store (acesso ao estado), next (referência ao próximo middleware ou reducer) e action, decidindo o que fazer: passar a ação, modificá-la ou bloqueá-la.
Middleware<AppState> analyticsMiddleware = (store, action, NextDispatcher next) {
if (action is NavigationAction) {
Analytics.logEvent(action.screenName);
}
return next(action);
};
final store = Store<AppState>>(
reducer,
initialState,
middleware: [analyticsMiddleware]
);
Exemplo de analyticsMiddleware em Dart para Flutter Redux. O middleware intercepta todos os NavigationAction, registra o nome da tela no sistema de análise e chama next(action) para continuar a cadeia. Se next não fosse chamada, a ação não chegaria ao reducer — assim é possível implementar navegação condicional ou bloquear ações indesejadas. A ordem do middleware no array determina a sequência de processamento.
Redux Thunk é um middleware que permite despachar não apenas objetos de ação mas também funções. A função recebe dispatch e getState, pode realizar operações assíncronas (requisições de API via cliente HTTP, leitura de BD) e despachar ações normais ao finalizar. Esta é a abordagem padrão para requisições de rede em aplicações Redux. Redux Saga usa geradores (yield) para cenários mais complexos: cancelamento de requisições, condições de corrida, operações paralelas e debounce de entrada do usuário. Segundo Redux Saga (2026), as corrotinas Saga são mais fáceis de testar e depurar que os callbacks aninhados do Thunk.
Ktor Client da JetBrains constrói o processamento HTTP baseado em pipeline middleware. Cada etapa da requisição — configuração de conexão, envio de cabeçalhos, leitura de resposta — é representada por uma fase separada no pipeline. O desenvolvedor instala plugins (middleware) via client.install { }, obtendo uma cadeia de processamento. A ordem de instalação determina qual middleware processa dados primeiro: Logging, Auth, ContentNegotiation, Caching.
val client = HttpClient {
install(Logging) {
level = LogLevel.BODY
}
install(Auth) {
bearer {
loadTokens { BearerTokens("access", "refresh") }
}
}
install(ContentNegotiation) {
json(Json { ignoreUnknownKeys = true })
}
install(HttpTimeout) {
requestTimeoutMillis = 15000
}
}
Configuração do Ktor Client com plugins middleware instalados. Logging — escreve o corpo da requisição e resposta. Auth — adiciona automaticamente o token Bearer com suporte a refresh. ContentNegotiation — serializa/desserializa JSON. HttpTimeout — define timeouts. Cada plugin é independente: em ambiente de teste pode-se desabilitar Auth substituindo a configuração do cliente sem alterar o código das requisições.
Dio é um cliente HTTP popular para Flutter, que usa Interceptor como middleware. Interceptor intercepta RequestOptions antes de enviar e Response após receber, suportando uma cadeia de múltiplos interceptadores. Dio Interceptor é análogo ao OkHttp Interceptor para Dart/Flutter. Segundo Dio (2026), RetryInterceptor e LogInterceptor são os middleware mais usados em projetos Flutter.
Bloc não tem middleware integrado como componente separado, mas o padrão é implementado via BlocObserver — um observador global que recebe eventos de cada bloco na aplicação. BlocObserver.onEvent é chamado antes de processar cada evento, onTransition em cada transição de estado, onError em cada exceção. É um middleware completo para análise, logging, relatórios de falhas e monitoramento de desempenho.
class AppBlocObserver extends BlocObserver {
@override
void onEvent(Bloc bloc, Object? event) {
Crashlytics.log("${bloc.runtimeType}: $event");
super.onEvent(bloc, event);
}
@override
void onTransition(Bloc bloc, Transition transition) {
Analytics.log(transition.eventName());
super.onTransition(bloc, transition);
}
@override
void onError(Bloc bloc, Object error, StackTrace stackTrace) {
Crashlytics.recordError(error, stackTrace);
super.onError(bloc, error, stackTrace);
}
}
BlocOverrides.runZoned(() {
runApp(MyApp());
}, blocObserver: AppBlocObserver());
Exemplo de AppBlocObserver — middleware para Bloc em Dart. onEvent registra cada evento no Crashlytics, onTransition envia eventos para análise, onError escreve exceções no relatório de falhas. A conexão via BlocOverrides.runZoned torna o observador global para todos os blocos sem alterar seu código. Para desabilitar em testes, basta passar um observador vazio ou não sobrescrever BlocOverrides.
Middleware é eficaz para tarefas que afetam muitos componentes: logging, autenticação, análise, cache, monitoramento de desempenho. Use middleware quando a mesma lógica se repete em diferentes partes da aplicação — adicionar um token a cada requisição, registrar cada ação do usuário, análise de cada transição de tela. Segundo Dio (2026), o processamento centralizado via middleware reduz bugs em 25% comparado a duplicar código em cada componente separadamente.
O erro mais frequente é ordem incorreta do middleware, quando o primeiro interceptador espera dados que o segundo adiciona. O segundo erro mais comum são operações bloqueantes em middleware na thread principal: escrita de arquivos, chamadas HTTP síncronas, criptografia. O terceiro é falta de tratamento de exceções: se um middleware lançar uma exceção, toda a cadeia quebra e a ação não chegará ao reducer ou a requisição não será enviada. Sempre envolva a lógica do middleware em try-catch e registre erros no Crashlytics ou Sentry sem quebrar a cadeia. Revise regularmente a cadeia de middleware durante revisões de código — isso previne a degradação da arquitetura.
Perguntas frequentes
Interceptor é um caso especial de middleware para comunicações HTTP. Middleware é um padrão mais amplo: pode manipular ações (Redux), eventos (Bloc), HTTP (Ktor) e qualquer fluxo de dados. Interceptor está sempre vinculado à camada de rede e só trabalha com Request/Response.
Use um método fábrica ou contêiner DI (Dagger, Koin, GetIt) que retorne um conjunto diferente de middleware para dev e prod. No Redux, passe um array vazio nos testes. No Ktor, use um HttpClient de teste sem plugins. O princípio principal é que o middleware não deve estar hardcoded.
Sim — o middleware modifica a ação antes de passá-la ao reducer ou ao próximo middleware. Por exemplo, Redux middleware pode adicionar metadados (userId, timestamp, deviceId) a cada ação sem alterar o código do dispatcher. A regra principal é não mutar o objeto original mas criar um novo através do operador spread.
No Ktor, os termos são intercambiáveis — Ktor Client middleware e plugin significam a mesma coisa. Cada plugin implementa HttpClientPlugin e é instalado via client.install { }. Todos os plugins são incorporados ao pipeline da requisição, formando uma cadeia de processamento.
Sobrescrevendo BlocObserver.onError — um manipulador global chamado em cada exceção em qualquer bloco. É uma alternativa ao try-catch em cada bloco: um middleware centralizado trata erros, escreve-os no Crashlytics e exibe um snackbar ao usuário.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também