Kaynak — adreslenebilir nesne
REST'te her veri parçası bir kaynaktır ve kendi URL'i vardır. /orders/42, tek bir siparişi; /orders ise koleksiyonu temsil eder.
Bir API, iki sistemin birbiriyle konuşması için üzerinde anlaşılmış bir sözleşmedir. İyi tasarlanmış bir API tahmin edilebilir davranır: aynı isteğe aynı yanıtı verir, hataları açıkça anlatır ve değişirken mevcut entegrasyonları kırmaz. Bu sayfada REST kaynak modelinden HTTP metotlarına, kimlik doğrulamadan versiyonlamaya, rate limiting'den webhook entegrasyonuna kadar temel kavramları birlikte ve adım adım yan yana koyduk.
API (Application Programming Interface), bir yazılımın yeteneklerini başka yazılımlara açan arayüzdür. Web API'lerinin büyük bölümü REST tarzında tasarlanır: her şey bir kaynaktır (kullanıcı, sipariş, fatura), her kaynağın bir adresi (URL) vardır ve bu kaynaklar üzerinde HTTP metotlarıyla işlem yaparsınız. İstemci bir istek gönderir, sunucu bir yanıt döner; iletişim durumsuzdur, yani her istek kendi başına anlaşılır olmalıdır.
GET /v1/orders/42 HTTP/1.1
Host: api.ornek.com
Authorization: Bearer eyJhbGc...
Accept: application/json
# kaynak: 42 numaralı sipariş
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 42,
"status": "shipped",
"total": 149.90
}
REST'te her veri parçası bir kaynaktır ve kendi URL'i vardır. /orders/42, tek bir siparişi; /orders ise koleksiyonu temsil eder.
Sunucu istekler arasında oturum hatırlamaz. Kimlik ve gerekli bağlam her isteğin içinde taşınır; bu, yatay ölçeklemeyi ve önbelleklemeyi kolaylaştırır.
Kaynağın o anki hali bir temsille (çoğunlukla JSON) taşınır. Content-Type ve Accept başlıkları formatı belirler.
HTTP metodu, kaynak üzerinde ne yapmak istediğinizi söyler: okuma, oluşturma, güncelleme veya silme. Önemli bir ayrım idempotency'dir: aynı isteği birden çok kez göndermenin sonucu değiştirmediği metotlar (GET, PUT, DELETE) güvenle tekrar denenebilir; POST ise genellikle her çağrıda yeni bir kayıt oluşturur. Yanıtın durum kodu da en az gövde kadar önemlidir — entegrasyonlar kararlarını çoğunlukla bu koda göre verir.
| Metot | Amaç | Idempotent? | Tipik yanıt |
|---|---|---|---|
GET |
Kaynağı okur, yan etkisi yoktur | Evet | 200 / 404 |
POST |
Koleksiyona yeni kaynak ekler | Hayır | 201 + Location |
PUT |
Kaynağı bütünüyle değiştirir | Evet | 200 / 204 |
PATCH |
Kaynağın bir kısmını günceller | Genelde | 200 / 204 |
DELETE |
Kaynağı siler | Evet | 204 / 404 |
200 OK okuma/güncellemede, 201 Created oluşturmada, 204 No Content ise gövdesiz başarıda kullanılır.
400 geçersiz istek, 401 kimliksiz, 403 yetkisiz, 404 bulunamadı, 409 çakışma. Sorun isteğin kendisindedir.
500 beklenmeyen hata, 503 geçici erişilemezlik. Burada hata sunucudadır; istemci genelde tekrar deneyebilir.
200 dönmeyin.
Hatayı gövdede {"error": ...} olarak verip durum kodunu 200 bırakmak, istemcinin başarı ile başarısızlığı ayırt etmesini imkânsızlaştırır. Doğru durum kodu, doğru gövdeden önce gelir.
İyi bir API, dokümantasyona bakmadan tahmin edilebilir. Bunun yolu tutarlı kaynak isimlendirmesinden geçer: çoğul isimler, fiil yerine isim, sığ ve öngörülebilir yollar. Büyük koleksiyonlar asla tek seferde dönmemeli; sayfalama, filtreleme ve sıralama net parametrelerle sunulmalıdır. Amaç, istemcinin sonraki adımı görmeden bilebilmesidir.
GET /v1/customers
POST /v1/customers
GET /v1/customers/17
GET /v1/customers/17/orders
GET /v1/orders?status=open&limit=25
# çoğul, isim, sığ; ilişki bir alt yol
POST /getCustomerById
POST /v1/createNewOrder
GET /v1/customer/17/getOrders
GET /v1/ALL-orders
# fiil yola girmiş, tekil/çoğul karışık,
# metot ile amaç çelişiyor
Büyük listeleri parçalayın. Offset tabanlı (?page=2) basittir; cursor tabanlı (?cursor=...) ise sık değişen verilerde kaymayı önler.
Sorgu parametreleriyle daraltma sunun: ?status=open, ?sort=-created_at. Parametre adlarını alan adlarıyla tutarlı tutun.
Liste yanıtlarını sabit bir yapıyla dönün: veri dizisi ve yanında toplam sayı, sonraki sayfa bilgisi. İstemci her endpoint için yeniden öğrenmek zorunda kalmaz.
API'nin önce kimi dinlediğini (authentication), sonra neye izin verdiğini (authorization) bilmesi gerekir. Sunucu-sunucu entegrasyonlarda API key veya istemci kimlik bilgisi yeterken; bir kullanıcı adına erişim için OAuth 2.0 ile alınan bearer token kullanılır. İzinler scope'larla daraltılır, böylece bir anahtar yalnızca işini yapacak kadar yetki taşır.
# 1) Token al
POST /oauth/token
grant_type=client_credentials
client_id=abc&client_secret=***
scope=orders:read
# 2) Token ile isteği imzala
GET /v1/orders
Authorization: Bearer eyJhbGc...
orders:read, invoices:write). En az yetki ilkesini uygulamanın pratik yoludur.Bir API yayımlandığı andan itibaren bir sözdür: başka ekipler ona göre kod yazar. Bu yüzden API'nizi makine-okunur bir sözleşmeyle (OpenAPI) tanımlamak ve değişiklikleri "kırıcı" mı değil mi diye sınıflandırmak kritiktir. Alan eklemek genelde güvenlidir; alan silmek, yeniden adlandırmak veya zorunlu kılmak ise mevcut istemcileri kırar ve yeni bir sürüm gerektirir.
openapi: 3.1.0
info:
title: Orders API
version: 1.4.0
paths:
/orders/{id}:
get:
summary: Tek sipariş getir
responses:
"200": { description: Başarılı }
"404": { description: Bulunamadı }
Tek bir sözleşme dosyasından dokümantasyon, istemci kütüphaneleri ve sözleşme testleri üretebilirsiniz. Sözleşme koddan ayrı yaşadığında, dokümantasyon ile gerçek davranış arasındaki sapma görünür olur.
/v1/... ve /v2/... yan yana yaşar. En görünür ve en yaygın yöntemdir; eski sürüm bir süre desteklenmeye devam eder.
İsteğe bağlı yeni alan eklemek, yeni endpoint açmak, yeni opsiyonel parametre eklemek. Mevcut istemciler etkilenmeden çalışmaya devam eder.
Bir alanı kaldırmadan önce duyurun, Deprecation başlığıyla işaretleyin ve geçiş için makul süre tanıyın.
Ağ güvenilmezdir: istekler kaybolur, gecikir veya tekrarlanır. Sağlam bir entegrasyon bunu varsayar. Sunucu tarafında rate limiting kötüye kullanımı sınırlar; istemci tarafında retry ve exponential backoff geçici hataları toparlar. İkisinin ortasında idempotency key durur: aynı isteğin iki kez işlenmesini önler. Diğer yönde ise webhook'lar, sizin sormanızı beklemeden olayları size iter.
HTTP/1.1 429 Too Many Requests
Retry-After: 2
RateLimit-Remaining: 0
RateLimit-Reset: 2
# istemci 2 sn bekleyip tekrar dener
POST /v1/payments
Idempotency-Key: a1b2-c3d4
# aynı key ile gelen ikinci istek
# yeni ödeme oluşturmaz; ilk yanıtı döner
# sağlayıcı sizin URL'inize olayı iter
POST /webhooks/payments
X-Signature: sha256=9f86d0...
{ "event": "payment.succeeded",
"id": "evt_123" }
# 1) imzayı paylaşılan sır ile doğrula
# 2) hızlıca 200 dön, işi kuyruğa al
Gelen webhook'un gerçekten sağlayıcıdan geldiğini, paylaşılan sırla hesaplanan imzayı karşılaştırarak doğrulayın. İmzasız bir uca güvenmeyin.
Webhook'lar en az bir kez teslim edilir; aynı olay iki kez gelebilir. Olay kimliğini saklayıp işlenmişse atlayın — alıcı tarafı idempotent olmalı.
API güvenliği tek bir önlemle değil, üst üste binen katmanlarla sağlanır: her isteği TLS üzerinden taşımak, gelen her girdiyi doğrulamak, yetkiyi kaynak düzeyinde kontrol etmek ve tarayıcı erişimini CORS ile bilinçli açmak. Üzerine de işletim gelir — her isteği ölçmeden hangi entegrasyonun yavaşladığını ya da hata aldığını göremezsiniz.
Token ve veri yalnızca şifreli kanaldan taşınmalı. Düz HTTP'yi kapatın; bearer token gibi gizli değerler asla şifresiz ağda dolaşmamalı.
Her alanı tip, uzunluk ve aralık olarak doğrulayın; beklenmeyen alanları reddedin. Sözleşmeye uymayan istek, iş mantığına ulaşmadan durmalı.
Kimliği doğrulanmış olmak yetmez. /orders/42 isteyen kullanıcının o siparişe erişebildiğini her seferinde kontrol edin — aksi hâlde bilgi sızar.
Tarayıcıdan çağrılacaksa yalnızca güvendiğiniz origin'lere izin verin. * ile her yere açmak, kötü amaçlı sitelerin API'nizi kullanmasına kapı aralar.
API key ve client secret'ları depoya commit etmeyin. Ortam değişkeni ya da bir secrets manager kullanın; sızıntıya karşı düzenli rotasyon planlayın.
Gecikme, hata oranı ve trafik hacmini endpoint bazında izleyin. Correlation ID'leri ile bir isteğin uçtan uca yolunu takip edin; sorun çıktığında nedeni hızlı bulun.
Authentication "sen kimsin?" sorusunu yanıtlar — kimliği doğrular. Authorization ise "neye iznin var?" sorusunu — yetkiyi belirler. Önce kimlik doğrulanır, sonra her kaynak için yetki kontrol edilir; biri diğerinin yerine geçmez.
PUT kaynağı bütünüyle değiştirir; gönderdiğiniz gövde kaynağın yeni tam halidir. PATCH ise yalnızca belirttiğiniz alanları günceller. Bir alanı yanlışlıkla boşaltmamak için kısmi güncellemede PATCH tercih edilir.
401 Unauthorized aslında "kimliğin yok ya da geçersiz" demektir — giriş yapmanız gerekir. 403 Forbidden ise "kimliğin var ama bu kaynağa yetkin yok" anlamına gelir. İsimleri yanıltıcı olsa da ayrım kimlik ile yetki arasındadır.
REST her kaynağı ayrı bir endpoint olarak sunar; istemci sabit yanıtları alır. GraphQL tek bir uçtan, istemcinin tam olarak istediği alanları sorgulamasına izin verir. Biri basitlik ve önbellekleme, diğeri esneklik tarafında güçlüdür; rakip değil, farklı denge noktalarıdır.
Safe metot kaynağı hiç değiştirmez (GET). Idempotent metot ise değiştirebilir ama aynı isteği tekrarlamak ek bir etki yaratmaz (PUT, DELETE). Her safe metot idempotenttir; ama her idempotent metot safe değildir.
HTTP, OAuth ve API güvenliğini tanımlayan IETF, OWASP ve OpenAPI gibi kuruluşların resmi belgeleri.
Sıfırdan bir API tasarlamaktan mevcut bir entegrasyonu sağlamlaştırmaya kadar; baştan iyi kurulmuş bir sözleşme, sonradan toparlamaktan her zaman kolaydır. Nereden başlayacağınıza birlikte bakalım.