Build a clean REST API in pure PHP — no framework required — responding with JSON based on HTTP method and URL.
header("Content-Type: application/json; charset=utf-8");
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type");
if ($_SERVER["REQUEST_METHOD"] === "OPTIONS") { exit(0); }
$method = $_SERVER["REQUEST_METHOD"];
$uri = trim(parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH), "/");
$parts = explode("/", $uri); // ["api", "posts", "5"]
$resource = $parts[1] ?? "";
$id = isset($parts[2]) && is_numeric($parts[2]) ? (int)$parts[2] : null;
function respond(int $status, array $body): never {
http_response_code($status);
echo json_encode($body, JSON_THROW_ON_ERROR);
exit;
}
match (true) {
$resource === "posts" && $method === "GET" && $id === null => respondAll(),
$resource === "posts" && $method === "GET" && $id !== null => respondOne($id),
$resource === "posts" && $method === "POST" => createOne(),
$resource === "posts" && $method === "PUT" && $id !== null => updateOne($id),
$resource === "posts" && $method === "DELETE" && $id !== null => deleteOne($id),
default => respond(404, ["error" => "Not found"])
};
function respondAll(): never {
respond(200, ["data" => getPosts()]);
}
function createOne(): never {
$body = json_decode(file_get_contents("php://input"), true, 512, JSON_THROW_ON_ERROR);
if (empty($body["title"])) {
respond(422, ["error" => "Title is required"]);
}
$id = createPost($body["title"], $body["body"] ?? "");
respond(201, ["id" => $id, "message" => "Created"]);
}