Membuat REST API dengan PHP Native Tanpa Framework (2026)
Framework seperti Laravel memang mempermudah development, tapi untuk API sederhana yang butuh performa maksimal dan zero dependency, PHP native adalah pilihan yang sangat viable. Artikel ini menunjukkan cara membangun REST API production-ready tanpa satu pun library eksternal.
1. Struktur Project
api/
boot.php # Bootstrap (headers, DB, helpers)
auth/
login.php # POST /api/auth/login
register.php # POST /api/auth/register
users/
me.php # GET /api/users/me
orders/
create.php # POST /api/orders/create
list.php # GET /api/orders/list
config/
db.php # PDO connection
helpers.php # Response helpers
.htaccess # URL routing
2. Bootstrap (boot.php)
header("Content-Type: application/json; charset=utf-8");
header("Access-Control-Allow-Origin: https://yourapp.com");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");
if ($_SERVER["REQUEST_METHOD"] === "OPTIONS") {
http_response_code(204); exit;
}
require_once __DIR__ . "/../config/db.php";
require_once __DIR__ . "/../config/helpers.php";
3. Response Helper
function resp($success, $message, $data = null, $code = 200) {
http_response_code($code);
echo json_encode([
"success" => (bool)$success,
"message" => $message,
"data" => $data
]);
exit;
}
function get_input() {
$raw = file_get_contents("php://input");
return json_decode($raw, true) ?: [];
}
4. Autentikasi Bearer Token
function require_auth($pdo) {
$header = $_SERVER["HTTP_AUTHORIZATION"] ?? "";
if (!preg_match("/Bearer (.+)/i", $header, $m)) {
resp(false, "Token required", null, 401);
}
$token_hash = hash("sha256", trim($m[1]));
$st = $pdo->prepare("SELECT u.* FROM sessions s
JOIN users u ON u.id = s.user_id
WHERE s.token = ? AND s.expires_at > NOW()");
$st->execute([$token_hash]);
$user = $st->fetch();
if (!$user) resp(false, "Invalid or expired token", null, 401);
return $user;
}
5. Rate Limiting
function check_rate_limit($pdo, $user_id, $action, $max = 60) {
$pdo->prepare("DELETE FROM rate_limits
WHERE created_at < NOW() - INTERVAL 1 MINUTE")->execute();
$st = $pdo->prepare("SELECT COUNT(*) FROM rate_limits
WHERE user_id=? AND action=?");
$st->execute([$user_id, $action]);
if ((int)$st->fetchColumn() >= $max) {
resp(false, "Rate limit exceeded", null, 429);
}
$pdo->prepare("INSERT INTO rate_limits (user_id, action)
VALUES (?, ?)")->execute([$user_id, $action]);
}
6. Contoh Endpoint
// api/orders/create.php
require_once __DIR__ . "/../boot.php";
if ($_SERVER["REQUEST_METHOD"] !== "POST") resp(false, "Method not allowed", null, 405);
$user = require_auth($pdo);
check_rate_limit($pdo, $user["id"], "order_create", 10);
$in = get_input();
$product_id = (int)($in["product_id"] ?? 0);
if (!$product_id) resp(false, "product_id required", null, 422);
// ... business logic ...
resp(true, "Order created", ["order_id" => $new_id], 201);
Kenapa Tanpa Framework?
- Performa - zero overhead, boot time < 1ms
- Kontrol penuh - tahu persis apa yang terjadi di setiap line
- Deployment simpel - upload file, selesai
- Cocok untuk microservice - API kecil yang fokus
Kesimpulan
PHP native bukan berarti primitif. Dengan pattern yang benar (separation of concerns, prepared statements, proper error handling), Anda bisa build API yang robust dan scalable. Pendekatan ini digunakan oleh OTPZap API yang melayani ratusan request per menit dengan response time konsisten di bawah 50ms - tanpa satu pun framework.