Middlewares em PHP: Interceptando o Ciclo de Requisição na Prática Já leu

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 . Veja um exemplo funcional: Middleware de Autenticação Um caso mais realista: validar token JWT antes de acessar recursos protegidos. Composição e Pipeline de Middlewares Encadeando Múltiplos Middlewares Na prática, você vai rodar vários middlewares em sequência.

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á.

Referências


Artigos relacionados