jekcms REST API'si tek bir PHP dosyasında çalışıyor. İsteğin nasıl ayrıştırıldığını, kimliğin nasıl doğrulandığını, listelerin nasıl sayfalandığını ve yeni bir uç noktanın nereye eklendiğini gerçek koddan anlatıyoruz.
API Nasıl Kurulu
jekcms REST API'si tek bir dosyada duruyor: api/v1/index.php. /api/v1/ ile başlayan her istek .htaccess içindeki tek bir kuralla bu dosyaya gidiyor:
RewriteRule ^api/v1/(.*)$ api/v1/index.php [QSA,L]
Dosyadaki Api sınıfı adresi parçalara ayırıyor. /api/v1/posts/42/revisions isteğinde ilk parça (posts) uç noktanın adı, geri kalanlar (42, revisions) parametre oluyor. İstek gövdesi JSON olarak okunuyor; GET isteklerinde adres sorgusundaki değerler de buna ekleniyor.
Her istek aynı sırayla işleniyor: önce istek sınırı kontrol ediliyor, sonra kimlik doğrulanıyor, ardından uç noktanın adına göre ilgili fonksiyon çağrılıyor:
private function route()
{
switch ($this->endpoint) {
case 'posts': return $this->handlePosts();
case 'media': return $this->handleMedia();
case 'categories': return $this->handleCategories();
case 'tags': return $this->handleTags();
case 'comments': return $this->handleComments();
case 'stats': return $this->handleStats();
case 'search': return $this->handleSearch();
case 'health': return $this->handleHealth();
// users, settings, webhook, trends, sitemap ...
default:
$this->error('Endpoint not found', 404);
return null;
}
}
Yeni Bir Uç Nokta Eklemek
Yeni bir uç nokta için iki şey gerekiyor: route() içinde bir case satırı ve isteği karşılayan bir fonksiyon. Fonksiyon bir dizi döndürüyor; JSON'a çevirme ve {"success": true, "data": ...} zarfına koyma işini sınıf kendisi yapıyor. Hata durumunda $this->error() çağrılıp null döndürülüyor.
Örnek olarak her kategorideki yayımlanmış yazı sayısını veren bir /api/v1/category-counts uç noktası:
// route() içine:
case 'category-counts': return $this->handleCategoryCounts();
// Sınıfa yeni fonksiyon:
private function handleCategoryCounts()
{
if ($this->method !== 'GET') {
$this->error('Method not allowed', 405);
return null;
}
return $this->db->fetchAll(
"SELECT c.slug, c.name, COUNT(p.id) AS posts
FROM categories c
LEFT JOIN post_categories pc ON pc.category_id = c.id
LEFT JOIN posts p ON p.id = pc.post_id AND p.status = 'published'
GROUP BY c.id ORDER BY c.name"
);
}
Benzer bir şey arıyorsanız önce mevcut uç noktalara bakın. Örneğin /api/v1/stats yazı, yorum, medya, kategori, etiket ve kullanıcı sayılarını zaten döndürüyor.
Bir uyarı: api/v1/index.php çekirdeğin parçası ve jekcms güncellemesi bu dosyayı yeniden yazıyor. Eklediğiniz kodu ayrı bir dosyada saklayın ve güncellemeden sonra tekrar ekleyin.
Kimlik Doğrulama
Kimlik doğrulama yönlendirmeden önce, her istek için tek bir yerde yapılıyor. Yeni uç noktanız bu yüzden ek kod yazmadan korunmuş oluyor. Anahtar üç yoldan gelebiliyor: X-API-Key başlığı, Authorization: Bearer ... başlığı ya da bazı istemcilerin gönderdiği Api-Key başlığı. Apache'nin bazı kurulumlarında Authorization başlığı PHP'ye ulaşmadığı için kod başlığı birkaç farklı kaynaktan okumayı deniyor.
Anahtarlar veritabanında düz metin olarak değil, SHA-256 özeti olarak tutuluyor ve gelen anahtar da özetlenerek karşılaştırılıyor. Webhook imzaları için oluşturulan anahtarlar API kimliği olarak kabul edilmiyor.
Kimliği doğrulanmış olmak yazma yetkisi için yetmiyor. İçerik değiştiren işlemler authorizeWrite() ile anahtarın bağlı olduğu kullanıcının rolüne bakıyor; yetkisi olmayan rol 403 alıyor. Yeni uç noktanız veri değiştiriyorsa aynı kontrolü siz de çağırın.
Sayfalama ve Filtreler
Yazı listesi page ve per_page parametrelerini kabul ediyor. per_page en fazla 100 olabiliyor. Filtre olarak status, type, category (kategori kısa adı; alt kategoriler de dahil), tag, author_id, search, date_from ve date_to kullanılabiliyor. Bütün değerler parametreli sorguyla veritabanına gidiyor; sorgu metnine elle eklenmiyor.
GET /api/v1/posts?category=haberler&status=published&page=2&per_page=20
Yanıt şu biçimde dönüyor:
{
"success": true,
"data": {
"items": [ ... ],
"total": 134,
"pages": 7,
"current_page": 2,
"per_page": 20
}
}
Kendi listeleme uç noktanızı yazarken aynı alan adlarını kullanmanız, istemci tarafında tek bir sayfalama kodunun her yerde çalışmasını sağlar.
İstek Sınırı
API her IP adresi için saatte varsayılan olarak 100 istek kabul ediyor. Sınır aşılınca 429 dönüyor. Değer API_RATE_LIMIT ayarıyla değiştirilebiliyor.
Dışarıya Bildirim Göndermek
Çekirdekteki webhook desteği gelen istekler için: n8n gibi bir araç api/v1/webhook/* üzerinden jekcms'e yazı gönderebiliyor ve istek HMAC-SHA256 imzasıyla doğrulanıyor. jekcms'in sitede bir şey olduğunda başka bir sisteme haber vermesini sağlayan genel bir giden webhook sistemi yok.
Uç noktanızın dış bir servise haber vermesi gerekiyorsa bunu kendiniz yazmanız gerekiyor. Hedef adresi ve ortak gizli anahtarı uygun bir yerde saklayın, gönderdiğiniz veriyi aynı yöntemle imzalayın ve karşı tarafın imzayı doğrulamasını sağlayın:
$payload = json_encode(['data' => $data, 'timestamp' => time()]);
$signature = hash_hmac('sha256', $payload, $secret);
// İstekle birlikte gönderin:
// X-Webhook-Signature: sha256=<signature>
Karşı servis kapalıysa API yanıtının beklememesi için isteğe kısa bir zaman aşımı verin ve hatayı kaydedin. Yeniden deneme gerekiyorsa bunu bir kuyrukla yapmak daha sağlıklı.