Proyecto: API REST con PHP
Este proyecto construye una API REST completa con PHP puro (sin frameworks), aplicando todo lo aprendido: manejo de rutas según la URL ($_SERVER["REQUEST_URI"]), lectura del método HTTP ($_SERVER["REQUEST_METHOD"]), recepción de JSON del body (json_decode(file_get_contents("php://input"))), acceso a la base de datos con PDO y prepared statements, y respuestas JSON con header("Content-Type: application/json"). Este es el núcleo de cómo funcionan frameworks como Laravel internamente.
Construir una API sin framework te enseña los fundamentos que los frameworks abstraen: cómo el servidor HTTP comunica la solicitud a PHP mediante variables superglobales ($_SERVER, $_GET, $_POST), cómo las respuestas HTTP tienen códigos de estado significativos (200 OK, 201 Created, 404 Not Found, 400 Bad Request), y cómo manejar errores devolviendo JSON en lugar de páginas de error.
Una vez que entiendes estos fundamentos, aprender Laravel es mucho más sencillo porque sabes qué está haciendo por ti.
<?php
// index.php - API REST con PHP puro
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE");
$method = $_SERVER["REQUEST_METHOD"];
$uri = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
$parts = explode("/", trim($uri, "/"));
$resource = $parts[1] ?? "";
$id = isset($parts[2]) ? (int)$parts[2] : null;
function getDb(): PDO {
static $pdo = null;
if ($pdo === null) {
$pdo = new PDO("sqlite:api.db", options: [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
$pdo->exec("CREATE TABLE IF NOT EXISTS tareas (
id INTEGER PRIMARY KEY AUTOINCREMENT,
titulo TEXT NOT NULL,
completada INTEGER DEFAULT 0
)");
}
return $pdo;
}
function responder(mixed $data, int $code = 200): never {
http_response_code($code);
echo json_encode($data, JSON_UNESCAPED_UNICODE);
exit;
}
function body(): array {
return json_decode(file_get_contents("php://input"), true) ?? [];
}
if ($resource === "tareas") {
$db = getDb();
match($method) {
"GET" => $id
? (($t = $db->prepare("SELECT * FROM tareas WHERE id=?")->execute([$id]))
? responder($t) : responder(["error"=>"No encontrada"], 404))
: responder($db->query("SELECT * FROM tareas")->fetchAll()),
"POST" => (function() use ($db) {
$b = body();
if (empty($b["titulo"])) responder(["error"=>"Título requerido"], 400);
$db->prepare("INSERT INTO tareas (titulo) VALUES (?)")->execute([$b["titulo"]]);
responder(["id"=>$db->lastInsertId(), "titulo"=>$b["titulo"]], 201);
})(),
"DELETE" => (function() use ($db, $id) {
if (!$id) responder(["error"=>"ID requerido"], 400);
$db->prepare("DELETE FROM tareas WHERE id=?")->execute([$id]);
responder(["ok" => true]);
})(),
default => responder(["error"=>"Método no permitido"], 405)
};
}
responder(["error"=>"Ruta no encontrada"], 404);
Practica esta lección
Resuelve los ejercicios del curso de PHP en la app, gratis y con corrección automática.
Empezar a practicar