Bugün mobil uygulamalardan mikroservislere kadar neredeyse tüm modern yazılımlar API'ler (Application Programming Interface) üzerinden iletişim kurar. Çalışan bir API yazmak kolaydır. Ancak ölçeklenebilir, güvenli ve öngörülebilir, diğer geliştiricilerin kullanmaktan keyif alacağı bir API tasarlamak, kanıtlanmış bazı standartlara uymayı gerektirir.

Bu rehberde gerçek projelerde en çok önem taşıyan REST API tasarım prensiplerini ele alıyor, ardından bir REST API'yi güvenli hale getirmek için pratik bir kontrol listesinden geçiyoruz.

REST API Tasarımında En İyi Pratikler

1. HTTP Metotlarını Doğru Kullanın

REST'in temeli, bir kaynak üzerindeki her işlem için doğru HTTP metodunu kullanmaktır. Her şey için POST kullanmak yaygın bir anti-pattern'dir.

  • GET: Veriyi okur veya listeler. Sunucuda hiçbir şeyi değiştirmemelidir.
  • POST: Yeni bir kaynak oluşturur.
  • PUT: Mevcut bir kaynağı tamamen değiştirir.
  • PATCH: Mevcut bir kaynağı kısmen günceller.
  • DELETE: Bir kaynağı siler.

GET, PUT ve DELETE idempotent'tir: aynı isteği iki kez göndermek, bir kez göndermekle aynı etkiye sahiptir. Bu, tekrar denemeleri güvenli hale getirir. İki kez çalışmaması gereken POST istekleri için (örneğin ödemeler) bir Idempotency-Key başlığı kabul edin ve aynı anahtarla gelen tekrarları yok sayın.

2. Uç Noktalarda Fiil Değil İsim Kullanın

URL'lerinizde get, create veya update gibi fiiller yerine kaynak isimleri (tercihen çoğul) kullanın. Yapılacak işlem zaten HTTP metodu ile belirtilir.

// Kötü kullanım ❌
POST /create-user
GET  /get-user-by-id/5

// İyi kullanım ✅
POST /users
GET  /users/5
GET  /users/5/orders      // iç içe kaynak: 5 numaralı kullanıcının siparişleri

URL'leri küçük harfle yazın, çok kelimeli isimlerde tire kullanın (/order-items) ve bir ya da iki seviyeden daha derin iç içe yapılardan kaçının.

3. Anlamlı HTTP Durum Kodları Döndürün

Her şey için 200 OK döndürüp hataları sadece JSON gövdesinde anlatmak kötü bir tasarımdır. İstemciler, proxy'ler ve izleme araçları standart durum kodlarını anlar:

  • 200 OK: İstek başarılı (GET, PUT, PATCH).
  • 201 Created: Yeni kaynak oluşturuldu (POST). Adresini Location başlığında döndürün.
  • 204 No Content: Başarılı, yanıt gövdesi yok (genellikle DELETE).
  • 400 Bad Request: İstek hatalı biçimlendirilmiş veya geçersiz.
  • 401 Unauthorized: Kimlik doğrulama eksik veya geçersiz.
  • 403 Forbidden: Kimlik doğrulandı, ancak bu işleme izin yok.
  • 404 Not Found: Kaynak mevcut değil.
  • 409 Conflict: İstek mevcut durumla çakışıyor (örneğin aynı e-posta zaten kayıtlı).
  • 422 Unprocessable Content: Biçimi doğru olan verideki doğrulama hataları.
  • 429 Too Many Requests: İstemci istek limitine ulaştı.
  • 500 Internal Server Error: Beklenmeyen bir sunucu hatası.

4. Tutarlı Bir Hata Formatı Kullanın

Her hata aynı yapıda olmalı ki istemciler hepsini tek bir kodla ele alabilsin. İyi bir seçenek standart Problem Details formatıdır (RFC 9457, application/problem+json):

{
  "type": "https://api.example.com/errors/validation",
  "title": "Validation failed",
  "status": 422,
  "detail": "The request contains invalid fields.",
  "errors": {
    "email": "The email field must contain a valid email address."
  }
}

5. Sayfalama, Filtreleme ve Sıralama Desteği Sunun

Asla sınırsız bir liste döndürmeyin. Büyük koleksiyonlar makul bir varsayılan ve azami sayfa boyutuyla sayfalanmalıdır:

GET /products?status=active&sort=-created_at&limit=20&cursor=eyJpZCI6MTIzfQ

Cursor tabanlı sayfalama büyük tablolarda hızlı kalır ve yeni kayıtlar eklendiğinde öğeleri atlamaz ya da tekrarlamaz. İstemcinin kendisi oluşturmak zorunda kalmaması için bir sonraki cursor'ı yanıtta döndürün.

6. API'nizi İlk Günden Versiyonlayın

Başka uygulamalar API'nize bağımlı hale geldiğinde er ya da geç geriye dönük uyumsuz değişiklikler yapmanız gerekecek. Baştan bir sürüm numarası ekleyin ki eski istemciler çalışmaya devam ederken yenileri bir sonraki sürüme geçebilsin:

GET https://api.example.com/v1/users

Ana sürümü sadece geriye dönük uyumsuz değişikliklerde artırın. Yeni ve isteğe bağlı bir alan eklemek uyumsuz bir değişiklik değildir; bir alanı kaldırmak veya yeniden adlandırmak ise öyledir.

7. API'yi Belgeleyin

Bir API ancak dokümantasyonu kadar iyidir. Uç noktaları, parametreleri, örnek istekleri ve hata yanıtlarını bir OpenAPI tanımında açıklayın. Tek bir dosyadan etkileşimli dokümantasyon, istemci SDK'ları ve sözleşme testleri üretilebilir.

Bir REST API Nasıl Güvenli Hale Getirilir?

API ister herkese açık ister dahili olsun, güvenlik en baştan tasarıma dahil edilmelidir. Aşağıdaki uygulamalar, çoğu OWASP API Security Top 10 listesinde yer alan en yaygın API açıklarını önler.

1. Her Yerde HTTPS Kullanın

API'yi sadece HTTPS (TLS) üzerinden sunun. Aksi halde token'lar, şifreler ve kişisel veriler düz metin olarak iletilir ve ele geçirilebilir. API istemcileri için HTTP'yi HTTPS'e yönlendirmek yeterli değildir; düz HTTP isteklerini reddedin ve HSTS'yi etkinleştirin.

2. Standart Protokollerle Kimlik Doğrulayın

Kendi kimlik doğrulama yönteminizi icat etmeyin. OAuth 2.0 (kullanıcı girişi için OpenID Connect ile) ya da JWT gibi imzalı token'lar kullanın. Erişim token'larını kısa ömürlü tutun, yenilemek için refresh token kullanın ve token'ları asla URL'de değil, Authorization: Bearer başlığında gönderin; URL'deki token'lar loglara ve tarayıcı geçmişine düşer.

Bir JWT'yi doğrularken imzayı, beklenen algoritmayı, geçerlilik süresini (exp), yayıncıyı (issuer) ve hedef kitleyi (audience) mutlaka kontrol edin. Sunucudan sunucuya entegrasyonlarda API anahtarları yeterli olabilir, ancak bunları hash'leyerek saklayın ve yenilenebilir olmalarını sağlayın.

3. Her Nesnede Yetki Kontrolü Yapın

En yaygın API açığı bozuk giriş sistemi değil, eksik yetki kontrolleridir. GET /invoices/1042 faturayı mevcut kullanıcıya ait olup olmadığını kontrol etmeden döndürüyorsa, herkes numarayı değiştirerek diğer kullanıcıların verilerini okuyabilir. Bu açık Broken Object Level Authorization (BOLA) olarak bilinir.

// ❌ URL'deki ID'ye güveniyor
$invoice = $invoiceModel->find($id);

// ✅ Sorguyu giriş yapmış kullanıcıyla sınırlıyor
$invoice = $invoiceModel->where('id', $id)
                        ->where('user_id', $currentUser->id)
                        ->first();

if ($invoice === null) {
    return $this->failNotFound();
}

Aynı mantığı alanlara da uygulayın: istemcinin role veya is_admin gibi özellikleri sadece istek gövdesinde gönderdiği için değiştirmesine asla izin vermeyin. Yalnızca açıkça izin verilen alanları kabul edin.

4. Tüm Girdileri Doğrulayın

İstemci zaten doğrulasa bile her parametrenin, başlığın ve gövde alanının tipini, uzunluğunu, formatını ve izin verilen değerlerini sunucuda doğrulayın. SQL injection saldırılarını önlemek için veritabanı erişiminde parametreli sorgular veya bir query builder kullanın ve azami istek gövdesi boyutu belirleyin.

5. İstek Limiti (Rate Limiting) Uygulayın

İstek limiti API'yi kaba kuvvet (brute-force) saldırılarından, veri kazıma (scraping) ve kazara aşırı yüklenmeden korur. İstekleri API anahtarı, kullanıcı veya IP başına sınırlayın (örneğin dakikada 60 istek), giriş ve şifre sıfırlama uç noktalarına daha sıkı limitler uygulayın ve limit aşıldığında Retry-After başlığıyla birlikte 429 Too Many Requests döndürün.

6. CORS'u Dikkatli Yapılandırın

Tarayıcılar API'nizi başka alan adlarından çağırıyorsa, sadece güvendiğiniz kaynaklara (origin) izin verin. Çerez kullanan veya özel veri döndüren uç noktalarda Access-Control-Allow-Origin: * kullanmaktan kaçının.

7. Hata Mesajlarında Bilgi Sızdırmayın

Hata yanıtları saldırgana değil, istemcinin isteği düzeltmesine yardımcı olmalıdır. Canlı ortamda asla stack trace, SQL hatası, dosya yolu veya framework sürümü döndürmeyin. Ayrıntıları sunucuda loglayın ve istemcinin bildirebileceği bir istek kimliğiyle (request ID) birlikte genel bir mesaj döndürün.

8. Loglayın, İzleyin ve Gizli Bilgileri Koruyun

Başarısız kimlik doğrulamaları, yetki hatalarını ve olağan dışı trafiği loglayın, ani artışlar için uyarı kurun. Veritabanı şifreleri ve imzalama anahtarları gibi gizli bilgileri depoda değil, ortam değişkenlerinde veya bir secret manager'da tutun ve düzenli olarak yenileyin.

REST API Güvenlik Kontrol Listesi

  • Tüm trafik HSTS etkin şekilde HTTPS üzerinden sunuluyor.
  • Kimlik doğrulama OAuth 2.0 / OpenID Connect ya da düzgün doğrulanan kısa ömürlü token'larla yapılıyor.
  • Her uç nokta, kullanıcının ilgili nesneye ve alanlara erişim yetkisini kontrol ediyor.
  • Tüm girdiler sunucuda doğrulanıyor ve veritabanı erişimi parametreli yapılıyor.
  • İstek limitleri mevcut ve kimlik doğrulama uç noktalarında daha sıkı.
  • CORS sadece güvenilen kaynaklara izin veriyor.
  • Hatalar asla stack trace veya iç ayrıntıları göstermiyor.
  • Gizli bilgiler kodun dışında saklanıyor ve yenilenebiliyor.
  • Güvenlik olayları loglanıyor ve izleniyor.

Sonuç

Kaliteli bir yazılım sadece veritabanı veya backend mantığıyla değil, dış dünyaya açtığı arayüzün kalitesiyle de ölçülür. Tutarlı URL'ler, doğru durum kodları, öngörülebilir hatalar, sayfalama ve versiyonlama bir API'yi kullanımı keyifli hale getirir; HTTPS, standart kimlik doğrulama, nesne seviyesinde yetkilendirme, doğrulama ve istek limiti ise onu güvende tutar. CodeBlanks olarak WantAPI dahil kendi projelerimizi de bu standartlar üzerine inşa ediyoruz. Temiz kod yazmaya devam!