O Que São Middlewares e Por Que Importam
Middlewares são funções ou classes que interceptam a requisição HTTP antes dela chegar ao seu controlador e/ou manipulam a resposta após o processamento. Imagine um fluxo linear: cliente → servidor → resposta. Os middlewares atuam como porteiros inteligentes nesse fluxo, permitindo validações, autenticações, logs e transformações de dados sem sujar sua lógica principal.
Em PHP, especialmente em frameworks modernos como Laravel e Slim, middlewares seguem um padrão clássico: recebem a requisição, podem modificá-la ou rejeitá-la, e passam adiante (ou interrompem). Essa abordagem torna o código mais modular, reutilizável e testável — três pilares de qualidade que você vai querer em produção.
Anatomia e Implementação Prática
Middleware Simples em PSR-15
O padrão PSR-15 define a interface MiddlewareInterface. Veja um exemplo funcional:
<?php
namespace App\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class LoggerMiddleware implements MiddlewareInterface
{
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
// Antes da requisição
$startTime = microtime(true);
$method = $request->getMethod();
$path = $request->getUri()->getPath();
echo "[LOG] {$method} {$path} iniciado\n";
// Passa para o próximo middleware/handler
$response = $handler->handle($request);
// Depois da requisição
$duration = microtime(true) - $startTime;
echo "[LOG] {$method} {$path} finalizado em {$duration}s\n";
return $response;
}
}
Middleware de Autenticação
Um caso mais realista: validar token JWT antes de acessar recursos protegidos.
<?php
namespace App\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
class AuthMiddleware implements MiddlewareInterface
{
private string $secret = 'sua-chave-secreta';
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
$header = $request->getHeaderLine('Authorization');
if (!$header || !preg_match('/Bearer\s+(.+)/i', $header, $matches)) {
return $this->unauthorized();
}
try {
$token = $matches[1];
$decoded = JWT::decode($token, new Key($this->secret, 'HS256'));
// Adiciona usuário à requisição
$request = $request->withAttribute('user', $decoded);
return $handler->handle($request);
} catch (\Exception $e) {
return $this->unauthorized();
}
}
private function unauthorized(): ResponseInterface
{
$response = new \GuzzleHttp\Psr7\Response(401);
$response->getBody()->write(json_encode([
'error' => 'Unauthorized'
]));
return $response->withHeader('Content-Type', 'application/json');
}
}
Composição e Pipeline de Middlewares
Encadeando Múltiplos Middlewares
Na prática, você vai rodar vários middlewares em sequência. Frameworks como Slim fazem isso nativamente:
<?php
require 'vendor/autoload.php';
use Slim\Factory\AppFactory;
$app = AppFactory::create();
// Ordem importa! Middlewares são executados de cima para baixo
$app->add(new App\Middleware\LoggerMiddleware());
$app->add(new App\Middleware\AuthMiddleware());
$app->add(new App\Middleware\CorsMiddleware());
$app->get('/api/users', function ($request, $response) {
$user = $request->getAttribute('user');
$response->getBody()->write(json_encode([
'message' => "Olá, {$user->name}"
]));
return $response->withHeader('Content-Type', 'application/json');
});
$app->run();
Middleware com Parâmetros
Às vezes você precisa configurar um middleware dinamicamente:
<?php
namespace App\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class RateLimitMiddleware implements MiddlewareInterface
{
private int $requestsPerMinute;
public function __construct(int $requestsPerMinute = 60)
{
$this->requestsPerMinute = $requestsPerMinute;
}
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
$ip = $request->getServerParams()['REMOTE_ADDR'];
$key = "rate_limit:{$ip}";
// Simula verificação em cache (Redis ideal)
$requests = apcu_fetch($key) ?: 0;
if ($requests >= $this->requestsPerMinute) {
$response = new \GuzzleHttp\Psr7\Response(429);
$response->getBody()->write('Too Many Requests');
return $response;
}
apcu_store($key, $requests + 1, 60);
return $handler->handle($request);
}
}
// Uso com parâmetro
$app->add(new App\Middleware\RateLimitMiddleware(100));
Casos de Uso Comuns e Boas Práticas
Quando (e Quando Não) Usar Middlewares
Use middlewares para: autenticação, autorização, logging, CORS, rate limiting, compressão de resposta, validação de headers. Não use para lógica de negócio complexa — isso fica no controlador ou serviço.
Middleware é transversal; controlador é vertical. Mantenha essa separação clara e seu código será muito mais legível quando estiver debugando em produção às 2 da manhã.
Ordem de Execução
Lembre-se: middlewares executam de cima para baixo na requisição e de baixo para cima na resposta. Se você adicionar CORS antes de Auth, clientes não autenticados conseguirão fazer preflight requests — provavelmente o que você quer. Mas se adicionar um middleware que encripta a resposta antes de Logger, o log não conseguirá ler o corpo. Pense sempre na sequência.
// ❌ Errado: Logger vem depois de encriptação
$app->add(new EncryptMiddleware());
$app->add(new LoggerMiddleware()); // Vê corpo criptografado
// ✅ Correto: Logger vem antes
$app->add(new LoggerMiddleware()); // Vê corpo claro
$app->add(new EncryptMiddleware());
Conclusão
Middlewares são um dos padrões mais poderosos em arquitetura web moderna. Você aprendeu que: (1) middlewares interceptam requisições e respostas, permitindo lógica transversal sem poluir controladores; (2) o padrão PSR-15 oferece uma interface padronizada e reutilizável entre frameworks; (3) a ordem de execução é crítica e deve refletir sua lógica de negócio.
Da próxima vez que precisar autenticar um usuário ou logar requisições, pense em middleware primeiro. Seu código futuro agradecerá.