Suas ideias em realidade digital!
Middleware é uma camada que roda antes (e às vezes depois) do seu controller. Ele serve para centralizar regras repetidas como:
Sem middleware, você acaba copiando o mesmo código em todos os endpoints. Com middleware, você cria um pipeline (cadeia) e reaproveita.
/public/api/index.php
/src/Core/Router.php
/src/Core/Response.php
/src/Core/Request.php
/src/Middleware/MiddlewareInterface.php
/src/Middleware/MiddlewareQueue.php
/src/Middleware/JsonMiddleware.php
/src/Middleware/CorsMiddleware.php
/src/Middleware/AuthMiddleware.php
/src/Middleware/RateLimitMiddleware.php
/src/Controllers/...
method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$this->path = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/';
$this->headers = $this->readHeaders();
$this->query = $_GET ?? [];
$this->ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
}
private function readHeaders(): array {
$h = [];
foreach ($_SERVER as $k => $v) {
if (str_starts_with($k, 'HTTP_')) {
$name = str_replace('_', '-', strtolower(substr($k, 5)));
$h[$name] = $v;
}
}
// Authorization às vezes vem em outro server var
if (!isset($h['authorization']) && isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
$h['authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
}
return $h;
}
public function json(): array {
if ($this->body !== null) return (array)$this->body;
$raw = file_get_contents('php://input');
$data = json_decode($raw ?: '', true);
$this->body = is_array($data) ? $data : [];
return $this->body;
}
public function header(string $name, string $default = ''): string {
$key = strtolower($name);
return $this->headers[$key] ?? $default;
}
}
$message];
if ($details !== null) $payload['details'] = $details;
self::json($payload, $code);
}
}
Um middleware recebe o Request e um $next (próximo passo do pipeline).
3) MiddlewareQueue (pipeline)
Este é o motor que executa a cadeia.
stack = $stack;
}
public function run(Request $req, callable $finalHandler) {
$runner = array_reduce(
array_reverse($this->stack),
function($next, $mw) {
return function(Request $req) use ($mw, $next) {
return $mw->handle($req, $next);
};
},
$finalHandler
);
return $runner($req);
}
}
4) Middlewares prontos (os mais úteis)
4.1) JsonMiddleware (garante JSON em tudo)
4.2) CorsMiddleware (com preflight OPTIONS)
origin}");
header("Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");
header("Access-Control-Allow-Credentials: true");
if ($req->method === 'OPTIONS') {
http_response_code(200);
exit;
}
return $next($req);
}
}
4.3) AuthMiddleware (Bearer/JWT) aplicado só em rotas protegidas
Você pode aplicar em um grupo de rotas ou individualmente.
Aqui vai uma versão simples que exige Bearer em certas rotas.
protectedPrefixes as $p) {
if (str_starts_with($req->path, $p)) {
return $this->check($req, $next);
}
}
return $next($req);
}
private function check(Request $req, callable $next) {
$auth = $req->header('authorization', '');
if (!preg_match('/Bearer\\s+(.*)$/i', $auth, $m)) {
Response::error('Unauthorized', 401);
}
$token = trim($m[1]);
// Aqui você valida JWT ou token no banco:
// $payload = validateJWT($token, 'SEGREDO');
// if (!$payload) Response::error('Token inválido', 401);
return $next($req);
}
}
4.4) RateLimitMiddleware (por rota + IP)
Versão simplificada (você pode ligar na sua implementação Redis/MySQL do post anterior).
path;
$ip = $req->ip;
$rule = $this->rules[$routeKey] ?? ['max' => 120, 'window' => 60];
// Aqui você chama rateLimitRedis(...) ou rateLimitMySQL(...)
// $r = rateLimitRedis($redis, $routeKey, $ip, $rule['max'], $rule['window']);
// Exemplo fake:
$r = ['allowed' => true, 'remaining' => 999, 'retry_after' => 0];
header("X-RateLimit-Remaining: {$r['remaining']}");
if (!$r['allowed']) {
http_response_code(429);
header("Retry-After: {$r['retry_after']}");
echo json_encode(['error' => 'Too Many Requests', 'retry_after' => $r['retry_after']]);
exit;
}
return $next($req);
}
}
5) Integrando tudo no index.php da API
No seu /public/api/index.php, você cria o Request, roda o pipeline e por fim chama o router/controller.
['max' => 5, 'window' => 60],
'/api/auth/refresh' => ['max' => 20, 'window' => 3600],
]),
new AuthMiddleware(['/api/posts', '/api/private']),
];
$queue = new MiddlewareQueue($middlewares);
$queue->run($req, function(Request $req) {
$router = new Router();
// registre rotas...
// $router->get('/api/health', fn() => Response::json(['ok' => true]));
$router->dispatch($req->method, $req->path);
});
Boas práticas (pra não virar bagunça)
- Middleware deve ser pequeno e focado (uma responsabilidade)
- Evite colocar regra de negócio em middleware
- Use prefixos de rotas protegidas
- Centralize headers CORS/JSON
- Padronize erro e resposta