Membuat REST API dengan PHP Native Tanpa Framework (2026)

Tutorials 20 Mei 2026 · OTPZap Team

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?

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.