İyi tasarlanmış bir API'yi kullanmak keyiflidir; kötü tasarlanmış olanı ise her istekte yeniden çözülmesi gereken bir bulmacaya döner. Bu yazıda REST API best practices başlığı altında, kaynak isimlendirmesinden HTTP metotlarına, durum kodlarından versiyonlamaya kadar günlük geliştirmede gerçekten işine yarayacak ilkeleri toplu halde ele alıyorum. Amaç, başka geliştiricilerin (ve altı ay sonraki kendinin) belgeye bakmadan tahmin edebileceği, tutarlı ve öngörülebilir bir arayüz kurmaktır.
Kaynakları isimlendirme: isimler, fiiller değil
REST'in temel fikri, sistemini kaynaklar (resources) etrafında modellemektir. Endpoint yolları fiil değil isim içermeli ve koleksiyonlar için çoğul kullanılmalıdır. Eylemi HTTP metodu belirtir; yola eylem koymak gereksiz tekrar yaratır.
- İyi:
GET /users,GET /users/42,POST /users - Kötü:
GET /getUsers,POST /createUser,GET /user/list
İç içe kaynaklarda ilişkiyi yolda göster: bir kullanıcının siparişleri için GET /users/42/orders okunabilir ve mantıklıdır. Ancak iç içe yapıyı iki seviyeden fazla derinleştirme; /users/42/orders/7/items/3/reviews gibi yollar bakımı zorlaştırır. Bunun yerine alt kaynağa doğrudan erişim sun: GET /order-items/3. URL'lerde küçük harf ve tire kullan (/order-items), alt çizgi veya camelCase'ten kaçın.
HTTP metotlarını anlamına uygun kullan
Her metodun açık bir sözleşmesi vardır ve bu sözleşmeye uymak, ara katmanların (cache, proxy, tarayıcı) doğru davranmasını sağlar.
- GET — kaynak okur, yan etkisi yoktur (güvenli ve idempotent).
- POST — yeni kaynak oluşturur; idempotent değildir (iki kez çağırırsan iki kayıt oluşur).
- PUT — kaynağın tamamını değiştirir; idempotenttir (aynı isteği tekrarlamak sonucu değiştirmez).
- PATCH — kaynağın bir bölümünü günceller.
- DELETE — kaynağı siler; idempotenttir.
Pratik kural: GET asla veri değiştirmesin. "Silme" işlemini GET /users/42/delete gibi bir uca koymak yaygın ama yanlıştır; çünkü bir tarayıcı ön getirmesi veya bir crawler farkında olmadan kaydı silebilir. Tam güncellemede PUT, kısmi güncellemede PATCH tercih et.
Doğru durum kodlarını döndür
Durum kodu, yanıt gövdesini okumadan ne olduğunu anlatan ilk sinyaldir. Sürekli 200 OK dönüp gövdede {"success": false} yazmak istemciyi körleştirir. En sık kullanacağın kodlar:
- 200 OK — başarılı GET/PUT/PATCH.
- 201 Created — POST ile kaynak oluştu;
Locationbaşlığında yeni kaynağın adresini ver. - 204 No Content — başarılı ama gövdesi olmayan yanıt (genelde DELETE).
- 400 Bad Request — istek hatalı veya doğrulamadan geçmedi.
- 401 Unauthorized — kimlik doğrulanmadı; 403 Forbidden — kimlik doğrulandı ama yetki yok.
- 404 Not Found — kaynak yok.
- 409 Conflict — çakışma (örn. tekrar eden e-posta).
- 422 Unprocessable Entity — söz dizimi doğru ama anlamsal doğrulama başarısız (birçok framework bunu doğrulama hataları için kullanır).
- 429 Too Many Requests — hız sınırı aşıldı.
- 500 Internal Server Error — sunucu tarafı beklenmeyen hata.
401 ile 403 arasındaki farkı doğru kullan: ilki "kim olduğunu bilmiyorum", ikincisi "kim olduğunu biliyorum ama buna iznin yok" demektir.
Tutarlı ve makinece okunabilir hatalar
Her hatayı aynı yapıda döndürmek, istemcinin tek bir hata işleme rutini yazabilmesini sağlar. İnsan için bir message, makine için stabil bir code ve alan bazlı doğrulama detayları ver:
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{
"error": {
"code": "validation_failed",
"message": "Gönderilen veriler geçersiz.",
"fields": {
"email": ["Geçerli bir e-posta adresi girin."],
"age": ["18 veya daha büyük olmalı."]
}
}
}
code alanını sabit ve dilden bağımsız tut (validation_failed), message alanını ise kullanıcıya gösterilebilecek metin için kullan. Üretim ortamında 500 hatalarının iç ayrıntılarını (stack trace, SQL) sızdırma; bunun yerine destekle eşleştirmek için bir request_id dön.
Versiyonlama: değişimi kırmadan yönet
API'n yayında olduğu andan itibaren, geriye dönük uyumluluğu bozan her değişiklik mevcut istemcileri kırar. Bu yüzden bir versiyonlama stratejisi en baştan belirlenmelidir. En yaygın ve en görünür yöntem, sürümü yola koymaktır:
GET /v1/users
GET /v2/users
Alternatif olarak sürümü bir başlıkta taşıyabilirsin (Accept: application/vnd.api+json; version=2); bu daha "saf" kabul edilir ama keşfedilmesi ve test edilmesi zordur. Çoğu ekip için URL tabanlı sürümleme pratik ve nettir. Önemli ilke şudur: alan eklemek genellikle kırıcı değildir, ama alan kaldırmak, yeniden adlandırmak veya türünü değiştirmek kırıcıdır ve yeni bir sürüm gerektirir. Eski sürümler için bir kullanımdan kaldırma (deprecation) takvimi yayınla.
Listeleme uçları: sayfalama, filtreleme, sıralama
Bir koleksiyonu olduğu gibi döndürmek küçük veri setlerinde işe yarar ama tablo büyüdükçe hem sunucuyu hem istemciyi boğar. Listeleme uçlarına en baştan sayfalama ekle. İki yaygın yaklaşım vardır:
- Offset tabanlı:
GET /users?page=3&per_page=20— basittir, sayfa numarasına atlamaya izin verir; ancak veri sık değişiyorsa kayma (drift) yaşanır. - Cursor tabanlı:
GET /users?limit=20&cursor=eyJpZCI6MTQ0fQ— büyük ve sık değişen veri setlerinde daha kararlı ve performanslıdır.
Filtreleme ve sıralamayı sorgu parametreleriyle ver: GET /users?status=active&sort=-created_at. Sıralamada başına eklenen - azalan sırayı belirtmek için yaygın bir konvansiyondur. Yanıtta toplam sayı ve sonraki sayfa bilgisini bir meta bloğunda döndürmek, istemcinin gezinmesini kolaylaştırır.
Birkaç ek ilke
- Her yerde HTTPS: Token ve kişisel veri taşıyan bir API yalnızca TLS üzerinden çalışmalıdır.
- JSON tutarlılığı: Alan adlandırmasında tek bir stile bağlı kal (
snake_caseya dacamelCase) ve API boyunca değiştirme. - Tarihler için ISO 8601 ve UTC:
2026-06-27T14:30:00Zformatı belirsizliği ortadan kaldırır. - Belgeleme: OpenAPI (Swagger) ile makinece okunabilir bir şema yayınla; bu hem dokümantasyon hem de istemci kodu üretimi sağlar.
- Hız sınırı ve kimlik doğrulama: Kötüye kullanımı engellemek için rate limiting ekle ve durumunu uygun başlıklarla bildir.
Sık Sorulan Sorular
PUT mı PATCH mı kullanmalıyım?
Kaynağın tamamını gönderip yerine koyuyorsan PUT, yalnızca değişen birkaç alanı gönderiyorsan PATCH kullan. PUT idempotenttir: aynı tam gövdeyi defalarca göndermek sonucu değiştirmez. PATCH ise kısmi güncelleme içindir ve gövdesi yalnızca değişecek alanları taşır.
Versiyonu URL'de mi yoksa başlıkta mı tutmalıyım?
İkisi de geçerlidir. URL tabanlı sürümleme (/v1/...) keşfedilmesi ve tarayıcıda test edilmesi kolay olduğu için çoğu ekibin tercihidir. Başlık tabanlı sürümleme REST saflığına daha yakındır ama araç desteği ve görünürlük açısından daha zahmetlidir. Tutarlı olduğun sürece her ikisi de doğrudur.
Her şeye 200 dönüp gövdede hata belirtsem olmaz mı?
Olmaz. HTTP durum kodları tam da bu iş için vardır; cache katmanları, proxy'ler ve istemci kütüphaneleri bu kodlara göre davranır. Hatalar için 4xx/5xx kullanmak, istemcinin yanıt gövdesini ayrıştırmadan doğru kararı vermesini sağlar ve gözlemlenebilirliği artırır.
API'ni sıfırdan tasarlamak ya da mevcut uçlarını standartlara taşımak mı istiyorsun? Kaynak modellemesinden versiyonlama ve dokümantasyona kadar temiz, tutarlı bir REST arayüzü kurmana yardımcı olabilirim. Benimle iletişime geç ve projenin API'sini birlikte sağlamlaştıralım.