
XHR'nin callback cehennemini ve karmaşık sözdizimini gördük. Şimdi modern JavaScript'in sunduğu çok daha temiz bir çözümle tanışma zamanı: Fetch API.
Fetch, tarayıcılarda yerleşik olarak gelen, Promise tabanlı bir HTTP istek aracıdır. Kurulum gerektirmez, modern ve okunabilir bir sözdizimine sahiptir.
Fetch Nedir?
Fetch API, JavaScript'te HTTP isteği yapmak için kullanılan modern yöntemdir. 2015 yılında tarayıcılara eklendi.
Temel Özellikleri
- Promise tabanlı -
.then()veasync/awaitkullanabilirsiniz - Yerleşik - Ekstra kütüphane gerektirmez
- Temiz sözdizimi - Okunması ve yazması kolay
- Modern - Tüm güncel tarayıcılarda çalışır
En Basit Kullanım
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then(response => response.json())
.then(data => console.log(data));3 satırda bir API isteği! XHR ile aynı işlem 10+ satırdı.
Fetch Nasıl Çalışır?
Adım 1: İstek Gönder
fetch("https://jsonplaceholder.typicode.com/users/1")fetch() bir Promise döndürür. Bu Promise, sunucudan herhangi bir yanıt geldiğinde (başarılı veya hata) resolve olur.
Adım 2: Response Nesnesini Al
fetch("https://jsonplaceholder.typicode.com/users/1")
.then(response => {
console.log(response);
});Response nesnesi şunları içerir:
status- Durum kodu (200, 404, vb.)ok- Başarılı mı? (status 200-299 arası ise true)headers- Yanıt başlıklarıbody- Yanıt gövdesi (henüz okunmamış!)
Adım 3: Body'yi Oku
Response'un body'si ReadableStream formatındadır. JSON'a çevirmek için .json() metodunu kullanırız:
fetch("https://jsonplaceholder.typicode.com/users/1")
.then(response => response.json()) // Body'yi JSON olarak parse et
.then(data => {
console.log(data); // Artık JavaScript nesnesi
});Önemli: .json() metodu da bir Promise döndürür. Bu yüzden ikinci bir .then() gerekiyor.
Tam Örnek: Kullanıcı Getirme
fetch("https://jsonplaceholder.typicode.com/users/1")
.then(response => {
console.log("Status:", response.status);
console.log("OK:", response.ok);
return response.json();
})
.then(kullanici => {
console.log("İsim:", kullanici.name);
console.log("Email:", kullanici.email);
console.log("Şehir:", kullanici.address.city);
})
.catch(error => {
console.log("Hata:", error);
});Çıktı:
Status: 200
OK: true
İsim: Leanne Graham
Email: Sincere@april.biz
Şehir: GwenboroughHata Yönetimi
Dikkat: 404 Hata Değildir!
Fetch'te önemli bir nokta: HTTP hata kodları (404, 500 vb.) catch'e düşmez!
fetch("https://jsonplaceholder.typicode.com/users/999999")
.then(response => {
console.log("Status:", response.status); // 404
console.log("OK:", response.ok); // false
return response.json();
})
.then(data => {
console.log("Data:", data); // {} boş obje
})
.catch(error => {
// Buraya düşmez! 404 bir HTTP yanıtıdır, ağ hatası değil.
console.log("Catch:", error);
});Doğru Hata Kontrolü
fetch("https://jsonplaceholder.typicode.com/users/999999")
.then(response => {
if (!response.ok) {
throw new Error(`HTTP Hatası: ${response.status}`);
}
return response.json();
})
.then(data => {
console.log(data);
})
.catch(error => {
console.log("Hata yakalandı:", error.message);
});catch Ne Zaman Çalışır?
- Ağ bağlantısı yoksa
- DNS çözümlenemezse
- CORS hatası varsa
throwile hata fırlatılırsa
async/await ile Fetch
Promise zinciri yerine async/await kullanmak kodu daha okunabilir yapar:
Temel Kullanım
async function kullaniciGetir(id) {
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
const kullanici = await response.json();
console.log(kullanici);
}
kullaniciGetir(1);Hata Yönetimi ile
async function kullaniciGetir(id) {
try {
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
if (!response.ok) {
throw new Error(`Kullanıcı bulunamadı: ${response.status}`);
}
const kullanici = await response.json();
console.log("İsim:", kullanici.name);
console.log("Email:", kullanici.email);
} catch (error) {
console.log("Hata:", error.message);
}
}
kullaniciGetir(1); // Başarılı
kullaniciGetir(999); // Hata: Kullanıcı bulunamadı: 404Ardışık İstekler
XHR'de callback hell oluyordu. Fetch ile çok daha temiz:
Promise Zinciri ile
fetch("https://jsonplaceholder.typicode.com/users/1")
.then(response => response.json())
.then(kullanici => {
console.log("Kullanıcı:", kullanici.name);
return fetch(`https://jsonplaceholder.typicode.com/users/${kullanici.id}/posts`);
})
.then(response => response.json())
.then(postlar => {
console.log("Post sayısı:", postlar.length);
return fetch(`https://jsonplaceholder.typicode.com/posts/${postlar[0].id}/comments`);
})
.then(response => response.json())
.then(yorumlar => {
console.log("İlk postun yorum sayısı:", yorumlar.length);
})
.catch(error => {
console.log("Hata:", error);
});Düz bir zincir - iç içe değil!
async/await ile (Daha da Temiz)
async function kullaniciBilgileriGetir(userId) {
try {
// 1. Kullanıcıyı getir
const userResponse = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`);
const kullanici = await userResponse.json();
console.log("Kullanıcı:", kullanici.name);
// 2. Postlarını getir
const postsResponse = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}/posts`);
const postlar = await postsResponse.json();
console.log("Post sayısı:", postlar.length);
// 3. İlk postun yorumlarını getir
const commentsResponse = await fetch(`https://jsonplaceholder.typicode.com/posts/${postlar[0].id}/comments`);
const yorumlar = await commentsResponse.json();
console.log("İlk postun yorum sayısı:", yorumlar.length);
} catch (error) {
console.log("Hata:", error);
}
}
kullaniciBilgileriGetir(1);Sanki senkron kod gibi okunuyor!
Paralel İstekler
Birbirini beklemeyen istekleri paralel yaparak zaman kazanabilirsiniz:
async function tumVerileriGetir() {
try {
// Aynı anda üç istek başlat
const [usersRes, postsRes, commentsRes] = await Promise.all([
fetch("https://jsonplaceholder.typicode.com/users"),
fetch("https://jsonplaceholder.typicode.com/posts"),
fetch("https://jsonplaceholder.typicode.com/comments")
]);
// Hepsini JSON'a çevir
const [users, posts, comments] = await Promise.all([
usersRes.json(),
postsRes.json(),
commentsRes.json()
]);
console.log("Kullanıcı sayısı:", users.length);
console.log("Post sayısı:", posts.length);
console.log("Yorum sayısı:", comments.length);
} catch (error) {
console.log("Hata:", error);
}
}
tumVerileriGetir();3 istek aynı anda gider, toplam süre en yavaş olanın süresi kadar olur.
POST İsteği
Veri göndermek için ikinci parametre olarak options objesi veririz:
fetch("https://jsonplaceholder.typicode.com/posts", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
title: "Yeni Başlık",
body: "Bu bir test içeriğidir.",
userId: 1
})
})
.then(response => response.json())
.then(data => {
console.log("Oluşturuldu:", data);
});async/await ile
async function yeniPostOlustur(baslik, icerik) {
try {
const response = await fetch("https://jsonplaceholder.typicode.com/posts", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
title: baslik,
body: icerik,
userId: 1
})
});
if (!response.ok) {
throw new Error("Post oluşturulamadı");
}
const yeniPost = await response.json();
console.log("Yeni post ID:", yeniPost.id);
return yeniPost;
} catch (error) {
console.log("Hata:", error.message);
}
}
yeniPostOlustur("Merhaba Dünya", "Bu benim ilk postum!");PUT ve DELETE İstekleri
PUT (Güncelleme)
async function postGuncelle(id, yeniBaslik) {
const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
id: id,
title: yeniBaslik,
body: "Güncellenmiş içerik",
userId: 1
})
});
const data = await response.json();
console.log("Güncellendi:", data);
}
postGuncelle(1, "Güncellenmiş Başlık");DELETE (Silme)
async function postSil(id) {
const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`, {
method: "DELETE"
});
if (response.ok) {
console.log("Post silindi!");
}
}
postSil(1);Header Ekleme
fetch("https://api.example.com/data", {
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer token123",
"X-Custom-Header": "custom-value"
}
});Fetch Options (Seçenekler)
fetch(url, {
method: "POST", // GET, POST, PUT, PATCH, DELETE
headers: { // İstek başlıkları
"Content-Type": "application/json"
},
body: JSON.stringify(data), // İstek gövdesi
mode: "cors", // cors, no-cors, same-origin
credentials: "include", // include, same-origin, omit
cache: "no-cache", // default, no-cache, reload, force-cache
redirect: "follow" // follow, manual, error
});Fetch'in Dezavantajları
1. JSON Otomatik Parse Edilmez
Her seferinde .json() çağırmalısınız:
// Her istekte iki await
const response = await fetch(url);
const data = await response.json();2. HTTP Hataları Otomatik Yakalanmaz
404, 500 gibi hatalar için manuel kontrol gerekir:
if (!response.ok) {
throw new Error(`HTTP Error: ${response.status}`);
}3. İstek Timeout Yok
Fetch'te yerleşik timeout özelliği yok. AbortController kullanmanız gerekir:
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
fetch(url, { signal: controller.signal })
.then(response => response.json())
.finally(() => clearTimeout(timeoutId));XHR vs Fetch Karşılaştırması
| Özellik | XHR | Fetch |
|---|---|---|
| Promise desteği | ❌ | ✅ |
| async/await | ❌ | ✅ |
| Sözdizimi | Karmaşık | Temiz |
| Yerleşik | ✅ | ✅ |
| Otomatik JSON | ❌ | ❌ |
| HTTP hata yakalama | Manuel | Manuel |
| Timeout | ✅ | ❌ (AbortController) |
| Progress olayları | ✅ | Sınırlı |
Özet
// GET
const response = await fetch(url);
const data = await response.json();
// POST
const response = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data)
});
// Hata kontrolü
if (!response.ok) {
throw new Error(`HTTP Error: ${response.status}`);
}Sırada Ne Var?
Fetch API güçlü bir araç ama hâlâ bazı dezavantajları var: manuel JSON parse, manuel hata kontrolü, timeout eksikliği...
Bir sonraki makalede tüm bu sorunları çözen ve geliştirici deneyimini bir üst seviyeye taşıyan Axios kütüphanesini öğreneceğiz.


