Belajar REST API PHP: Panduan Lengkap untuk Pemula

| | | PHP
Belajar REST API PHP: Panduan Lengkap untuk Pemula

REST API adalah arsitektur yang memungkinkan dua aplikasi berkomunikasi melalui HTTP. Dalam dunia web development, belajar REST API PHP sangat penting karena hampir semua aplikasi modern menggunakan API untuk pertukaran data — mulai dari mobile app, single page application, hingga integrasi dengan layanan pihak ketiga.

Dalam tutorial ini, kita akan membuat REST API sederhana dengan PHP murni (tanpa framework) yang mendukung operasi CRUD (Create, Read, Update, Delete) menggunakan metode HTTP.

Apa Itu REST API?

REST (Representational State Transfer) adalah gaya arsitektur yang menggunakan protokol HTTP untuk berkomunikasi. API yang mengikuti prinsip REST disebut RESTful API.

Prinsip utama REST API:

  • Stateless — setiap request berisi semua informasi yang dibutuhkan server
  • Client-Server — client dan server terpisah, bisa dikembangkan secara independen
  • Uniform Interface — menggunakan URL sebagai alamat resource
  • Resource-based — setiap entitas (user, produk, artikel) adalah resource yang diakses via URL

Metode HTTP dalam REST API

MetodeFungsiContoh
GETMengambil dataGET /api/produk — ambil semua produk
POSTMenambah data baruPOST /api/produk — buat produk baru
PUTMengupdate dataPUT /api/produk/1 — update produk ID 1
DELETEMenghapus dataDELETE /api/produk/1 — hapus produk ID 1

Format Data REST API

REST API biasanya menggunakan format JSON untuk pertukaran data. Contoh response:

{
    "status": "success",
    "message": "Data berhasil diambil",
    "data": [
        {
            "id": 1,
            "nama_produk": "Laptop Asus",
            "harga": 8500000,
            "stok": 15
        }
    ]
}

Persiapan

  • XAMPP atau Laragon yang sudah berjalan
  • PHP 7.4 atau lebih baru
  • MySQL database
  • Postman atau browser untuk testing

Langkah 1: Membuat Database

Buat database dan tabel di phpMyAdmin:

CREATE DATABASE rest_api_db;
USE rest_api_db;

CREATE TABLE produk (
    id INT AUTO_INCREMENT PRIMARY KEY,
    nama_produk VARCHAR(100) NOT NULL,
    harga INT NOT NULL,
    stok INT DEFAULT 0,
    deskripsi TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

INSERT INTO produk (nama_produk, harga, stok, deskripsi) VALUES
('Laptop Asus VivoBook', 8500000, 15, 'Laptop 14 inch RAM 8GB SSD 512GB'),
('Mouse Logitech M185', 150000, 50, 'Mouse wireless nano receiver'),
('Keyboard Mechanical Rexus', 450000, 30, 'Keyboard mechanical switch blue'),
('Monitor LG 24 inch', 2100000, 10, 'Monitor IPS Full HD 75Hz'),
('Webcam Logitech C270', 350000, 25, 'Webcam HD 720p dengan mic');

Langkah 2: Struktur Folder API

rest-api/
├── config/
│   └── database.php
├── api/
│   └── produk.php
└── .htaccess

Langkah 3: Koneksi Database

Buat file config/database.php:

<?php
class Database {
    private $host = 'localhost';
    private $dbname = 'rest_api_db';
    private $username = 'root';
    private $password = '';
    private $pdo;

    public function koneksi() {
        try {
            $this->pdo = new PDO(
                "mysql:host={$this->host};dbname={$this->dbname};charset=utf8",
                $this->username,
                $this->password
            );
            $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
            return $this->pdo;
        } catch (PDOException $e) {
            $this->response('error', 'Koneksi database gagal: ' . $e->getMessage(), null, 500);
        }
    }
}

Langkah 4: Membuat REST API

Buat file api/produk.php — ini adalah file utama API kita:

<?php
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, Authorization');

// Handle preflight request
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}

require_once '../config/database.php';

$database = new Database();
$pdo = $database->koneksi();

// Mendapatkan method HTTP (GET, POST, PUT, DELETE)
$method = $_SERVER['REQUEST_METHOD'];

// Mendapatkan URL path untuk routing
$request = explode('/', trim($_SERVER['PATH_INFO'] ?? '', '/'));
$resource = $request[0] ?? '';
$id = isset($request[1]) ? (int)$request[1] : null;

// Mendapatkan input JSON dari request body
$input = json_decode(file_get_contents('php://input'), true);

// Routing berdasarkan method dan resource
switch ($method) {
    case 'GET':
        if ($id) {
            getProdukById($pdo, $id);
        } else {
            getAllProduk($pdo);
        }
        break;

    case 'POST':
        tambahProduk($pdo, $input);
        break;

    case 'PUT':
        if ($id) {
            updateProduk($pdo, $id, $input);
        } else {
            response('error', 'ID produk harus disertakan', null, 400);
        }
        break;

    case 'DELETE':
        if ($id) {
            hapusProduk($pdo, $id);
        } else {
            response('error', 'ID produk harus disertakan', null, 400);
        }
        break;

    default:
        response('error', 'Method tidak didukung', null, 405);
}

// ===== FUNGSI-FUNGSI API =====

// GET /api/produk — Ambil semua produk
function getAllProduk($pdo) {
    try {
        $stmt = $pdo->query('SELECT * FROM produk ORDER BY id DESC');
        $data = $stmt->fetchAll();
        response('success', 'Data produk berhasil diambil', $data);
    } catch (PDOException $e) {
        response('error', 'Gagal mengambil data: ' . $e->getMessage(), null, 500);
    }
}

// GET /api/produk/{id} — Ambil produk berdasarkan ID
function getProdukById($pdo, $id) {
    try {
        $stmt = $pdo->prepare('SELECT * FROM produk WHERE id = ?');
        $stmt->execute([$id]);
        $data = $stmt->fetch();

        if ($data) {
            response('success', 'Produk ditemukan', $data);
        } else {
            response('error', 'Produk dengan ID ' . $id . ' tidak ditemukan', null, 404);
        }
    } catch (PDOException $e) {
        response('error', 'Gagal mengambil data: ' . $e->getMessage(), null, 500);
    }
}

// POST /api/produk — Tambah produk baru
function tambahProduk($pdo, $input) {
    // Validasi input
    if (empty($input['nama_produk']) || !isset($input['harga'])) {
        response('error', 'Nama produk dan harga wajib diisi', null, 400);
        return;
    }

    try {
        $stmt = $pdo->prepare('INSERT INTO produk (nama_produk, harga, stok, deskripsi) VALUES (?, ?, ?, ?)');
        $stmt->execute([
            $input['nama_produk'],
            (int)$input['harga'],
            (int)($input['stok'] ?? 0),
            $input['deskripsi'] ?? ''
        ]);

        $id = $pdo->lastInsertId();

        // Ambil data yang baru dimasukkan
        $stmt = $pdo->prepare('SELECT * FROM produk WHERE id = ?');
        $stmt->execute([$id]);
        $data = $stmt->fetch();

        response('success', 'Produk berhasil ditambahkan', $data, 201);
    } catch (PDOException $e) {
        response('error', 'Gagal menambah produk: ' . $e->getMessage(), null, 500);
    }
}

// PUT /api/produk/{id} — Update produk
function updateProduk($pdo, $id, $input) {
    try {
        // Cek apakah produk ada
        $stmt = $pdo->prepare('SELECT * FROM produk WHERE id = ?');
        $stmt->execute([$id]);
        $existing = $stmt->fetch();

        if (!$existing) {
            response('error', 'Produk dengan ID ' . $id . ' tidak ditemukan', null, 404);
            return;
        }

        // Update data
        $nama = $input['nama_produk'] ?? $existing['nama_produk'];
        $harga = $input['harga'] ?? $existing['harga'];
        $stok = $input['stok'] ?? $existing['stok'];
        $deskripsi = $input['deskripsi'] ?? $existing['deskripsi'];

        $stmt = $pdo->prepare('UPDATE produk SET nama_produk = ?, harga = ?, stok = ?, deskripsi = ? WHERE id = ?');
        $stmt->execute([$nama, $harga, $stok, $deskripsi, $id]);

        // Ambil data yang sudah diupdate
        $stmt = $pdo->prepare('SELECT * FROM produk WHERE id = ?');
        $stmt->execute([$id]);
        $data = $stmt->fetch();

        response('success', 'Produk berhasil diupdate', $data);
    } catch (PDOException $e) {
        response('error', 'Gagal update produk: ' . $e->getMessage(), null, 500);
    }
}

// DELETE /api/produk/{id} — Hapus produk
function hapusProduk($pdo, $id) {
    try {
        // Cek apakah produk ada
        $stmt = $pdo->prepare('SELECT * FROM produk WHERE id = ?');
        $stmt->execute([$id]);
        $data = $stmt->fetch();

        if (!$data) {
            response('error', 'Produk dengan ID ' . $id . ' tidak ditemukan', null, 404);
            return;
        }

        $stmt = $pdo->prepare('DELETE FROM produk WHERE id = ?');
        $stmt->execute([$id]);

        response('success', 'Produk berhasil dihapus', $data);
    } catch (PDOException $e) {
        response('error', 'Gagal hapus produk: ' . $e->getMessage(), null, 500);
    }
}

// Fungsi helper untuk mengirim response JSON
function response($status, $message, $data, $code = 200) {
    http_response_code($code);
    echo json_encode([
        'status' => $status,
        'message' => $message,
        'data' => $data,
        'timestamp' => date('Y-m-d H:i:s')
    ], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
    exit;
}

Penjelasan kode:

  • header('Content-Type: application/json') — memberitahu client bahwa response berupa JSON
  • Access-Control-Allow-Origin: * — mengizinkan akses dari domain lain (CORS)
  • $_SERVER['REQUEST_METHOD'] — mendeteksi metode HTTP yang digunakan
  • $_SERVER['PATH_INFO'] — mengambil path URL untuk routing (misal /produk/1)
  • json_decode(file_get_contents('php://input')) — membaca data JSON dari request body (untuk POST/PUT)
  • response() — fungsi helper untuk mengirim response JSON standar

Langkah 5: File .htaccess (Opsional)

Buat file .htaccess di folder api/ untuk URL rewriting:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ produk.php [QSA,L]

Langkah 6: Testing API dengan Postman

Test GET — Ambil semua produk

  • Method: GET
  • URL: http://localhost/rest-api/api/produk
  • Expected: JSON berisi daftar semua produk

Test GET — Ambil produk by ID

  • Method: GET
  • URL: http://localhost/rest-api/api/produk/1
  • Expected: JSON berisi data produk dengan ID 1

Test POST — Tambah produk baru

  • Method: POST
  • URL: http://localhost/rest-api/api/produk
  • Body (raw JSON):
{
    "nama_produk": "Headset Sony WH-1000XM4",
    "harga": 4200000,
    "stok": 8,
    "deskripsi": "Headset wireless noise cancelling premium"
}

Test PUT — Update produk

  • Method: PUT
  • URL: http://localhost/rest-api/api/produk/1
  • Body (raw JSON):
{
    "harga": 9000000,
    "stok": 12
}

Test DELETE — Hapus produk

  • Method: DELETE
  • URL: http://localhost/rest-api/api/produk/5
  • Expected: JSON berisi data produk yang dihapus

Testing API dengan cURL (Command Line)

Jika kamu lebih suka command line, bisa gunakan cURL:

# GET semua produk
curl -X GET http://localhost/rest-api/api/produk

# GET produk by ID
curl -X GET http://localhost/rest-api/api/produk/1

# POST tambah produk
curl -X POST http://localhost/rest-api/api/produk \
  -H "Content-Type: application/json" \
  -d '{"nama_produk":"Tablet Samsung","harga":3500000,"stok":20,"deskripsi":"Tablet 10 inch"}'

# PUT update produk
curl -X PUT http://localhost/rest-api/api/produk/1 \
  -H "Content-Type: application/json" \
  -d '{"harga":9000000}'

# DELETE hapus produk
curl -X DELETE http://localhost/rest-api/api/produk/1

Testing API dengan JavaScript (Fetch)

// GET semua produk
fetch('http://localhost/rest-api/api/produk')
    .then(res => res.json())
    .then(data => console.log(data));

// POST tambah produk
fetch('http://localhost/rest-api/api/produk', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
        nama_produk: 'Tablet Samsung',
        harga: 3500000,
        stok: 20,
        deskripsi: 'Tablet 10 inch'
    })
})
.then(res => res.json())
.then(data => console.log(data));

// PUT update produk
fetch('http://localhost/rest-api/api/produk/1', {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ harga: 9000000 })
})
.then(res => res.json())
.then(data => console.log(data));

// DELETE hapus produk
fetch('http://localhost/rest-api/api/produk/1', {
    method: 'DELETE'
})
.then(res => res.json())
.then(data => console.log(data));

Menambahkan Autentikasi API Key

Untuk mengamankan API, tambahkan validasi API key:

// Cek API key di header
$api_key = $_SERVER['HTTP_X_API_KEY'] ?? '';
$valid_keys = ['key123abc', 'key456def', 'key789ghi'];

if (!in_array($api_key, $valid_keys)) {
    response('error', 'API key tidak valid', null, 401);
}

Client harus mengirim header X-API-Key: key123abc di setiap request.

Menambahkan Pagination

Untuk API dengan banyak data, tambahkan pagination:

function getAllProduk($pdo) {
    $page = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
    $per_page = isset($_GET['per_page']) ? min(100, max(1, (int)$_GET['per_page'])) : 10;
    $offset = ($page - 1) * $per_page;

    // Hitung total
    $total = $pdo->query('SELECT COUNT(*) FROM produk')->fetchColumn();

    // Ambil data dengan limit
    $stmt = $pdo->prepare('SELECT * FROM produk ORDER BY id DESC LIMIT ? OFFSET ?');
    $stmt->bindValue(1, $per_page, PDO::PARAM_INT);
    $stmt->bindValue(2, $offset, PDO::PARAM_INT);
    $stmt->execute();
    $data = $stmt->fetchAll();

    http_response_code(200);
    echo json_encode([
        'status' => 'success',
        'data' => $data,
        'pagination' => [
            'page' => $page,
            'per_page' => $per_page,
            'total' => $total,
            'total_pages' => ceil($total / $per_page)
        ]
    ], JSON_UNESCAPED_UNICODE);
    exit;
}

Menambahkan Pencarian

function getAllProduk($pdo) {
    $search = $_GET['search'] ?? '';

    if ($search) {
        $stmt = $pdo->prepare('SELECT * FROM produk WHERE nama_produk LIKE ? ORDER BY id DESC');
        $stmt->execute(['%' . $search . '%']);
    } else {
        $stmt = $pdo->query('SELECT * FROM produk ORDER BY id DESC');
    }

    $data = $stmt->fetchAll();
    response('success', 'Data produk', $data);
}

Status Code HTTP yang Umum

CodeArtiKapan Digunakan
200OKRequest berhasil
201CreatedData baru berhasil dibuat
400Bad RequestInput tidak valid
401UnauthorizedAPI key/token tidak valid
403ForbiddenTidak punya akses
404Not FoundResource tidak ditemukan
405Method Not AllowedMethod HTTP tidak didukung
500Internal Server ErrorError di server

Kesimpulan

Belajar REST API PHP mencakup beberapa konsep penting:

  1. Metode HTTP — GET (ambil), POST (tambah), PUT (update), DELETE (hapus)
  2. URL routing — setiap resource punya URL sendiri (/api/produk, /api/produk/1)
  3. JSON — format data yang digunakan untuk request dan response
  4. Status code — kode yang menunjukkan hasil request (200=ok, 404=tidak ada, dll)
  5. CORS — pengaturan agar API bisa diakses dari domain lain

REST API yang kita buat sudah mendukung operasi CRUD lengkap, validasi input, error handling, dan response JSON yang terstruktur. Dari sini kamu bisa mengembangkan dengan menambahkan autentikasi, pagination, pencarian, dan rate limiting sesuai kebutuhan.

Sigit N avatar
Tentang Sigit N
Full-stack developer & technical writer. Berpengalaman di PHP, Laravel, NodeJS, MySQL, dan Python. Aktif menulis tutorial pemrograman dan maintaining open-source projects di PemburuKode sejak 2021.