JavaScript Fetch API: Modern Web İstekleri Nasıl Yapılır?
Günümüz web uygulamaları, sunucudan veri almak ve sunucuya veri göndermek gibi birçok ağ iletişimini gerçekleştirmek zorundadır. Bu iletişimler, web sitelerinin dinamik olmasını, kullanıcıların gerçek zamanlı bilgiye ulaşmasını ve etkileşimli deneyimler yaşamasını sağlar. Eskiden bu işlemler için XMLHttpRequest gibi daha karmaşık ve eski nesil yöntemler kullanılırken, modern JavaScript dünyası bize çok daha zarif ve güçlü bir araç sunuyor: Fetch API. Fetch API, ağ isteklerini yönetmek için daha temiz bir söz dizimi ve daha iyi bir geliştirici deneyimi vaat eder. Bu makalede, Fetch API’nin temellerinden başlayarak, çeşitli senaryolarda nasıl kullanılacağına dair adım adım örnekler ve ileri düzey ipuçları ile konuyu derinlemesine inceleyeceğiz. Amacımız, bu güçlü API’yi tam olarak anlamanızı ve projelerinizde etkili bir şekilde kullanabilmenizi sağlamaktır.
Fetch API Nedir ve Neden Kullanmalısınız?
Fetch API, web tarayıcılarında yerleşik olarak bulunan, ağ istekleri yapmak için modern bir arayüzdür. Temel olarak, XMLHttpRequest‘in yerini almayı hedefleyen, Promise tabanlı bir çözüm sunar. Bu, ağ isteklerinin asenkron doğasını daha kolay yönetmenizi sağlar. Geliştiriciler için en büyük avantajı, söz diziminin daha basit ve okunabilir olmasıdır. XMLHttpRequest‘in olay dinleyicileri ve karmaşık yapısı yerine, Fetch API’de then() ve catch() gibi Promise metotları sayesinde isteklerin başarılı olup olmadığını veya bir hata oluşup oluşmadığını net bir şekilde yönetebilirsiniz.
Peki, neden Fetch API’yi tercih etmelisiniz? Öncelikle, daha modern ve standartlara uygun bir yaklaşımdır. Tarayıcılar tarafından geniş çapta desteklenir ve gelecekteki web standartlarının temelini oluşturur. İkinci olarak, Promise tabanlı olması sayesinde asenkron kodunuzu daha anlaşılır ve yönetilebilir hale getirir. Bu, özellikle birden fazla ağ isteğini eş zamanlı olarak yapmak veya bir isteğin sonucuna göre başka işlemler gerçekleştirmek istediğinizde büyük bir fark yaratır. Üçüncüsü, daha esnektir. İstek başlıklarını (headers), yöntemlerini (method), gövdesini (body) ve diğer birçok seçeneği kolayca yapılandırabilirsiniz. Bu esneklik, RESTful API’lerle etkileşim kurarken veya özel ağ protokollerini kullanırken size büyük avantaj sağlar. Son olarak, ayrıştırılmış bir mimariye sahiptir. İstek ve yanıt nesneleri ayrı ayrı ele alınır, bu da veriyi işleme sürecini daha modüler hale getirir.
Bu özellikler, Fetch API’yi sadece basit veri çekme işlemleri için değil, aynı zamanda karmaşık API entegrasyonları, gerçek zamanlı güncellemeler ve hatta dosya yükleme/indirme gibi gelişmiş senaryolar için de ideal bir araç haline getirir. Fetch API ile tanışmak, web geliştirme becerilerinizi bir üst seviyeye taşımanın ilk adımıdır.
Temel Fetch İstekleri: GET ve POST
Fetch API’nin en sık kullanılan yöntemleri GET ve POST’tur. Bir web uygulamasının temel işlevlerinden biri, sunucudan veri almak (GET) ve sunucuya veri göndermektir (POST). Fetch API ile bu işlemleri nasıl yapacağımıza yakından bakalım.
GET İstekleri ile Veri Alma
GET isteği, adından da anlaşılacağı gibi, belirtilen kaynaktan veri almak için kullanılır. Genellikle bir URL’ye yapılan bir istektir ve sunucu bu isteğe karşılık olarak istenen veriyi döndürür. Fetch API ile basit bir GET isteği yapmak oldukça kolaydır. Varsayılan olarak, fetch() fonksiyonu bir GET isteği yapar.
Örneğin, bir JSONPlaceholder API’sinden kullanıcı bilgilerini almak istediğimizi varsayalım.
<pre><code class="language-javascript">
fetch('https://jsonplaceholder.typicode.com/users/1')
.then(response => {
// İlk then bloğu, isteğin başarılı olup olmadığını kontrol eder.
// response.ok özelliği true ise, durum kodu 200-299 arasındadır.
if (!response.ok) {
throw new Error('Ağ yanıtı beklenen gibi değildi: ' + response.statusText);
}
// response.json() metodu, yanıt gövdesini JSON olarak ayrıştırır ve bir Promise döndürür.
return response.json();
})
.then(data => {
// İkinci then bloğu, JSON verisi başarıyla ayrıştırıldıktan sonra çalışır.
console.log('Kullanıcı Bilgileri:', data);
// Burada alınan veriyi DOM'a ekleyebilir veya başka işlemler yapabilirsiniz.
})
.catch(error => {
// Herhangi bir hata oluşursa (ağ hatası, ayrıştırma hatası vb.) bu blok çalışır.
console.error('Fetch işlemi sırasında bir hata oluştu:', error);
});
</code></pre>
Yukarıdaki kodda, fetch() fonksiyonuna istediğimiz URL’yi iletiyoruz. Döndürülen Promise’in ilk .then() bloğu, isteğin başarılı olup olmadığını kontrol eder. response.ok özelliği, HTTP durum kodunun başarılı aralıkta (200-299) olup olmadığını belirtir. Eğer bir hata varsa, bir Error fırlatırız. Başarılıysa, response.json() metodunu çağırarak yanıt gövdesini JSON formatında ayrıştırırız. Bu metot da bir Promise döndürür. İkinci .then() bloğu, JSON verisi başarıyla ayrıştırıldığında çalışır ve bu veriye erişim sağlarız. Son olarak, .catch() bloğu, istek sırasında oluşabilecek herhangi bir hatayı yakalamak için kullanılır. Bu, ağ bağlantı sorunları veya sunucu hataları gibi durumları yönetmemize yardımcı olur.
POST İstekleri ile Veri Gönderme
POST isteği, sunucuya veri göndermek için kullanılır. Bu, yeni bir kaynak oluşturmak, mevcut bir kaynağı güncellemek veya bir işlem gerçekleştirmek gibi çeşitli amaçlarla yapılabilir. POST isteği yaparken, fetch() fonksiyonuna isteğin konfigürasyonunu içeren ikinci bir argüman (bir obje) geçirmemiz gerekir. Bu obje içinde method, headers ve body gibi özellikleri belirtebiliriz.
Örneğin, yeni bir kullanıcı oluşturmak için POST isteği yapalım.
<pre><code class="language-javascript">
const newUser = {
name: 'Ahmet Yılmaz',
username: 'ahmetymz',
email: 'ahmet.yilmaz@example.com',
phone: '123-456-7890',
website: 'ahmet.com'
};
fetch('https://jsonplaceholder.typicode.com/users', {
method: 'POST', // İstek yöntemini belirtiyoruz
headers: {
'Content-Type': 'application/json' // Gönderdiğimiz verinin JSON formatında olduğunu belirtiyoruz
},
body: JSON.stringify(newUser) // JavaScript objesini JSON string'ine dönüştürüyoruz
})
.then(response => {
if (!response.ok) {
throw new Error('Ağ yanıtı beklenen gibi değildi: ' + response.statusText);
}
return response.json(); // Genellikle POST istekleri de yanıt olarak oluşturulan veriyi döndürür
})
.then(data => {
console.log('Kullanıcı başarıyla oluşturuldu:', data);
})
.catch(error => {
console.error('Kullanıcı oluşturma sırasında bir hata oluştu:', error);
});
</code></pre>
Burada dikkat edilmesi gereken birkaç önemli nokta var:
* method: 'POST': İstek yöntemini açıkça ‘POST’ olarak belirtiyoruz.
* headers: { 'Content-Type': 'application/json' }: Sunucuya gönderdiğimiz verinin türünü belirtiyoruz. Genellikle API’ler JSON formatında veri bekler.
* body: JSON.stringify(newUser): Göndereceğimiz JavaScript objesini JSON.stringify() metodu ile JSON string’ine dönüştürüyoruz. Fetch API, body özelliğine string veya FormData gibi veri türleri alabilir.
Sunucu, isteği başarıyla işlediğinde genellikle oluşturulan kaynağın bilgilerini içeren bir yanıt döndürür. Bu yanıtı da yine response.json() ile alıp işleyebiliriz. POST istekleri, kullanıcı kayıtları, yorum gönderme veya bir sipariş verme gibi birçok senaryoda kullanılır.
Fetch API ile Hata Yönetimi ve Durum Kodları
Web isteklerinde hata yönetimi, sağlam ve güvenilir uygulamalar geliştirmenin temel taşlarından biridir. Fetch API, Promise tabanlı yapısı sayesinde hata yönetimini oldukça kolaylaştırır. Ancak, fetch() fonksiyonunun kendisi sadece ağ bağlantısı kesintileri gibi düşük seviyeli hataları yakalar. HTTP durum kodları (örneğin, 404 Not Found, 500 Internal Server Error) ağ isteğinin kendisi başarılı olduğu için fetch() tarafından hata olarak algılanmaz. Bu nedenle, bu tür hataları kendimiz yönetmemiz gerekir.
Yukarıdaki örneklerde de gördüğümüz gibi, response.ok özelliğini kullanarak HTTP durum kodlarının başarılı aralıkta (200-299) olup olmadığını kontrol ediyoruz. Eğer response.ok false ise, bu genellikle bir istemci hatası (4xx) veya sunucu hatası (5xx) anlamına gelir. Bu durumda, durumu daha anlaşılır hale getirmek için özel bir Error nesnesi fırlatmak iyi bir pratiktir.
<pre><code class="language-javascript">
fetch('https://api.example.com/veriler')
.then(response => {
if (!response.ok) {
// Durum kodunu ve metnini içeren bir hata mesajı oluşturuyoruz.
// Bu, hata ayıklamayı kolaylaştırır.
throw new Error(HTTP hatası! Durum: ${response.status} ${response.statusText});
}
return response.json();
})
.then(data => {
console.log('Veriler alındı:', data);
})
.catch(error => {
// Burası hem ağ hatalarını hem de yukarıda fırlattığımız HTTP hatalarını yakalar.
console.error('Veri çekme işlemi başarısız oldu:', error.message);
// Kullanıcıya anlamlı bir hata mesajı gösterebilirsiniz.
// Örneğin: document.getElementById('hataMesaji').textContent = 'Veriler alınamadı, lütfen daha sonra tekrar deneyin.';
});
</code></pre>
Bu yaklaşım, hem ağ bağlantısı kesintileri gibi beklenmedik durumları hem de sunucudan gelen belirli hata kodlarını (404, 500 vb.) ayrı ayrı ele almamızı sağlar. .catch() bloğu, Promise zincirindeki herhangi bir noktada meydana gelen tüm hataları yakalar. Bu, kodunuzu daha sağlam hale getirir ve kullanıcılarınıza daha iyi bir deneyim sunmanıza yardımcı olur.
Ayrıca, bazı API’ler kendi hata yapılarını tanımlayabilir. Örneğin, bir hata durumunda bile 200 OK döndürebilir ve yanıt gövdesine bir hata mesajı veya kodu ekleyebilir. Bu gibi durumlarda, response.json() ile veriyi aldıktan sonra, verinin kendisi içindeki bir özelliği kontrol ederek hata durumunu belirlemeniz gerekebilir.
<pre><code class="language-javascript">
fetch('https://api.example.com/islem')
.then(response => response.json()) // Önce JSON'a çeviriyoruz
.then(data => {
if (data.basarili) { // API'nin kendi hata kontrolü
console.log('İşlem başarılı:', data.sonuc);
} else {
// API'nin belirttiği hata mesajını kullanıyoruz
throw new Error('API hatası: ' + data.mesaj);
}
})
.catch(error => {
console.error('İşlem sırasında hata oluştu:', error.message);
});
</code></pre>
Bu esneklik, Fetch API’yi farklı API tasarımlarıyla uyumlu hale getirir. Önemli olan, uygulamanızın ihtiyaçlarına ve entegre olduğunuz API’nin dokümantasyonuna göre uygun hata yönetimi stratejisini belirlemektir.
Fetch API ile Gelişmiş İstekler: Headers, Mode, Credentials
Fetch API, temel GET ve POST isteklerinin ötesinde, daha karmaşık ağ iletişimi senaryoları için de güçlü seçenekler sunar. Bunlardan bazıları headers, mode ve credentials gibi yapılandırma seçenekleridir. Bu seçenekler, isteklerimizi daha hassas bir şekilde kontrol etmemizi sağlar.
Headers (Başlıklar)
HTTP başlıkları, isteğin veya yanıtın içeriği hakkında ek bilgi taşır. Örneğin, Content-Type başlığı, isteğin gövdesinin hangi formatta olduğunu belirtir (örneğin, application/json). Authorization başlığı, kimlik doğrulama bilgilerini taşır. Fetch API ile başlıkları headers seçeneği aracılığıyla kolayca ayarlayabiliriz.
<pre><code class="language-javascript">
fetch('https://api.example.com/protected-resource', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN', // API anahtarınızı veya token'ınızı buraya ekleyin
'X-Custom-Header': 'MyValue' // Özel bir başlık ekleme
}
})
.then(response => {
if (!response.ok) {
throw new Error('Yetkilendirme hatası veya başka bir sorun.');
}
return response.json();
})
.then(data => {
console.log('Korunmuş veriler:', data);
})
.catch(error => {
console.error('İstek başarısız oldu:', error);
});
</code></pre>
Bu örnekte, Authorization başlığı ile bir API anahtarını veya bir OAuth token’ını gönderiyoruz. X-Custom-Header ise tamamen isteğe bağlı, kendi belirlediğimiz bir başlık örneğidir. Başlıklar, API’lerle etkileşim kurarken kimlik doğrulama, içerik türü belirtme veya özel meta veriler iletme gibi birçok amaçla kullanılır.
Mode (Mod)
mode seçeneği, isteğin nasıl işleneceğini belirler. En yaygın değeri cors‘tur (Cross-Origin Resource Sharing). Tarayıcılar, güvenlik nedeniyle farklı bir alan adından (origin) gelen isteklere varsayılan olarak izin vermez. CORS, bu kısıtlamayı aşmak için bir mekanizmadır.
* cors (varsayılan): Tarayıcı, isteğin CORS kurallarına uygun olup olmadığını kontrol eder. Eğer sunucu uygun başlıkları döndürmüyorsa, istek başarısız olabilir.
* no-cors: Bu modda yapılan istekler, tarayıcı tarafından kısıtlanmaz ancak yanıt gövdesine erişilemez. Bu genellikle bir servis çalıştırıcısı (service worker) ile kullanılır.
* same-origin: İstek sadece aynı alan adına yapıldığında başarılı olur. Farklı bir alana yapılırsa hata verir.
Genellikle, API’lerle çalışırken mode‘u varsayılan (cors) olarak bırakırsınız. Eğer bir CORS hatası alıyorsanız, bu genellikle sunucu tarafında yapılandırılması gereken bir sorundur.
Credentials (Kimlik Bilgileri)
credentials seçeneği, tarayıcının istekle birlikte çerezleri (cookies) ve kimlik doğrulama başlıklarını (Authorization) göndermesi gerekip gerekmediğini kontrol eder.
* omit (varsayılan): Tarayıcı, kimlik bilgileri göndermez.
* same-origin: Tarayıcı, sadece istek aynı alan adına yapılıyorsa kimlik bilgileri gönderir.
* include: Tarayıcı, istek aynı alan adına yapılmasa bile her zaman kimlik bilgileri gönderir. Bu, özellikle kimlik doğrulama gerektiren API’lerle çalışırken kullanışlıdır.
Örneğin, oturum çerezlerini kullanarak bir API’ye erişmek istiyorsanız credentials: 'include' kullanabilirsiniz.
<pre><code class="language-javascript">
fetch('https://api.example.com/user-profile', {
method: 'GET',
credentials: 'include' // Çerezleri de göndereceğimizi belirtiyoruz
})
.then(response => {
if (!response.ok) {
throw new Error('Profil bilgileri alınamadı.');
}
return response.json();
})
.then(data => {
console.log('Kullanıcı Profili:', data);
})
.catch(error => {
console.error('Profil alma hatası:', error);
});
</code></pre>
Bu gelişmiş seçenekler, Fetch API’yi daha karmaşık ve gerçek dünya senaryolarında kullanmamıza olanak tanır. API’lerle entegrasyon yaparken bu seçenekleri doğru anlamak, sorunsuz bir iletişim sağlamak için kritik öneme sahiptir.
Vaka Analizi: Bir Blog Uygulamasında Fetch API Kullanımı
Şimdi, Fetch API’yi gerçek bir senaryoda, basit bir blog uygulaması geliştirdiğimizi düşünerek nasıl kullanabileceğimizi inceleyelim. Bu blog uygulamasında, makaleleri listeleyecek, tek bir makaleyi görüntüleyecek ve yeni bir makale oluşturabileceğiz.
Senaryo 1: Makaleleri Listeleme (GET)
Kullanıcı blog ana sayfasına geldiğinde, tüm makalelerin bir listesini görmelidir. Bu, bir GET isteği ile yapılabilir.
<pre><code class="language-javascript">
// Makaleleri getiren fonksiyon
function makaleleriGetir() {
const makaleListesiElementi = document.getElementById('makaleListesi');
makaleListesiElementi.innerHTML = 'Yükleniyor...'; // Yükleme göstergesi
fetch('https://api.example.com/articles') // Makalelerin bulunduğu API uç noktası
.then(response => {
if (!response.ok) {
throw new Error(Makaleler getirilemedi. Durum: ${response.status});
}
return response.json();
})
.then(makaleler => {
makaleListesiElementi.innerHTML = ''; // Yükleme göstergesini temizle
if (makaleler.length === 0) {
makaleListesiElementi.innerHTML = '<p>Henüz hiç makale yok.</p>';
return;
}
makaleler.forEach(makale => {
const li = document.createElement('li');
li.innerHTML =
<h3>${makale.baslik}</h3>
<p>${makale.ozet}...</p>
<a href="/makale/${makale.id}">Devamını Oku</a>
;
makaleListesiElementi.appendChild(li);
});
})
.catch(error => {
console.error('Makale listesi çekme hatası:', error);
makaleListesiElementi.innerHTML = <p style="color: red;">Makaleler yüklenirken bir hata oluştu: ${error.message}</p>;
});
}
// Sayfa yüklendiğinde fonksiyonu çağır
document.addEventListener('DOMContentLoaded', makaleleriGetir);
</code></pre>
Bu örnekte, makaleleriGetir fonksiyonu, https://api.example.com/articles adresine bir GET isteği gönderir. Yanıt başarıyla alındığında, makaleler bir liste öğesi olarak makaleListesiElementi içine eklenir. Hata durumunda ise kullanıcıya bir hata mesajı gösterilir.
Senaryo 2: Tek Bir Makaleyi Görüntüleme (GET)
Kullanıcı bir makalenin başlığına tıkladığında, o makalenin tam içeriğini görüntülemek ister. Bu, makalenin ID’sini kullanarak başka bir GET isteği ile yapılır.
<pre><code class="language-javascript">
// URL'den makale ID'sini alan ve makaleyi getiren fonksiyon
function makaleGoster(makaleId) {
const makaleDetayElementi = document.getElementById('makaleDetay');
makaleDetayElementi.innerHTML = 'Makale yükleniyor...';
fetch(https://api.example.com/articles/${makaleId}) // ID'ye göre belirli makaleyi al
.then(response => {
if (!response.ok) {
if (response.status === 404) {
throw new Error('Bu makale bulunamadı.');
}
throw new Error(Makale getirilemedi. Durum: ${response.status});
}
return response.json();
})
.then(makale => {
makaleDetayElementi.innerHTML =
<h2>${makale.baslik}</h2>
<p>Yazar: ${makale.yazar}</p>
<p>${makale.icerik}</p>
;
})
.catch(error => {
console.error('Makale detayları çekme hatası:', error);
makaleDetayElementi.innerHTML = <p style="color: red;">Makale yüklenirken bir hata oluştu: ${error.message}</p>;
});
}
// Sayfa yüklendiğinde URL'den ID'yi alıp fonksiyonu çağır
document.addEventListener('DOMContentLoaded', () => {
const urlParcalari = window.location.pathname.split('/');
const makaleId = urlParcalari[urlParcalari.length - 1]; // Örneğin: /makale/123 -> 123
if (makaleId) {
makaleGoster(makaleId);
} else {
document.getElementById('makaleDetay').innerHTML = '<p>Lütfen geçerli bir makale ID'si belirtin.</p>';
}
});
</code></pre>
Bu senaryoda, URL’den dinamik olarak makale ID’sini alıp (/makale/123 gibi), https://api.example.com/articles/123 adresine bir GET isteği gönderiyoruz. 404 hatası gibi özel durumları da yönetiyoruz.
Senaryo 3: Yeni Bir Makale Oluşturma (POST)
Kullanıcı bir form aracılığıyla yeni bir makale yazıp gönderdiğinde, bu veriyi sunucuya göndermemiz gerekir. Bu, bir POST isteği ile yapılır.
<pre><code class="language-javascript">
const makaleFormu = document.getElementById('makaleFormu');
const baslikInput = document.getElementById('baslik');
const icerikTextarea = document.getElementById('icerik');
const mesajAlani = document.getElementById('formMesaji');
makaleFormu.addEventListener('submit', function(event) {
event.preventDefault(); // Formun varsayılan gönderilmesini engelle
const yeniMakale = {
baslik: baslikInput.value,
icerik: icerikTextarea.value,
yazar: 'Anonim' // Varsayılan veya kullanıcıdan alınan yazar bilgisi
};
mesajAlani.textContent = 'Makale kaydediliyor...';
fetch('https://api.example.com/articles', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(yeniMakale)
})
.then(response => {
if (!response.ok) {
throw new Error(Makale kaydedilemedi. Durum: ${response.status});
}
return response.json(); // Genellikle oluşturulan makalenin bilgilerini döndürür
})
.then(olusturulanMakale => {
mesajAlani.textContent = 'Makale başarıyla kaydedildi!';
baslikInput.value = ''; // Formu temizle
icerikTextarea.value = '';
// Kullanıcıyı yeni makalenin sayfasına yönlendirebiliriz
// window.location.href = /makale/${olusturulanMakale.id};
})
.catch(error => {
console.error('Makale kaydetme hatası:', error);
mesajAlani.textContent = Hata: ${error.message};
});
});
</code></pre>
Bu senaryoda, form gönderildiğinde event.preventDefault() ile varsayılan form gönderimi engellenir. Ardından, formdaki veriler toplanarak bir JavaScript objesi oluşturulur. Bu obje JSON.stringify() ile string’e çevrilir ve POST isteği ile API’ye gönderilir. Başarılı olduğunda, kullanıcıya bir başarı mesajı gösterilir ve form temizlenir.
Bu vaka analizi, Fetch API’nin bir web uygulamasının temel işlevlerini yerine getirmek için nasıl kullanılabileceğini göstermektedir. Veri alma, görüntüleme ve gönderme gibi işlemler, Fetch API’nin temiz söz dizimi ve Promise tabanlı yapısı sayesinde daha yönetilebilir hale gelir.
Fetch API ile Dosya Yükleme ve İndirme
Fetch API, sadece JSON veya metin verileriyle sınırlı değildir; aynı zamanda dosya yükleme ve indirme gibi ikili (binary) veri işlemleri için de kullanılabilir. Bu, özellikle kullanıcıların resim, belge veya diğer dosyaları uygulamalarınıza yüklemesine veya sunucudan dosya indirmesine olanak tanıyan özellikler geliştirmek istediğinizde önemlidir.
Dosya Yükleme
Dosya yüklemek için genellikle FormData nesnesi kullanılır. FormData, HTML formlarındaki verileri temsil eden bir yapıdır ve dosya alanlarını da içerebilir.
<pre><code class="language-javascript">
const dosyaYuklemeFormu = document.getElementById('dosyaYuklemeFormu');
const dosyaSecici = document.getElementById('dosyaSecici'); // <input type="file"> elementi
dosyaYuklemeFormu.addEventListener('submit', function(event) {
event.preventDefault();
const secilenDosya = dosyaSecici.files[0]; // Kullanıcının seçtiği ilk dosya
if (!secilenDosya) {
alert('Lütfen yüklemek için bir dosya seçin.');
return;
}
const formData = new FormData();
formData.append('dosya', secilenDosya); // 'dosya' API'nin beklediği alan adı olmalı
fetch('https://api.example.com/upload', {
method: 'POST',
// 'Content-Type' başlığını FormData ile otomatik olarak ayarlanır, bu yüzden burada belirtmeye gerek yok.
body: formData
})
.then(response => {
if (!response.ok) {
throw new Error(Dosya yükleme başarısız. Durum: ${response.status});
}
return response.json(); // Sunucudan gelen yanıtı işleyin
})
.then(data => {
console.log('Dosya başarıyla yüklendi:', data);
alert('Dosya başarıyla yüklendi!');
})
.catch(error => {
console.error('Dosya yükleme hatası:', error);
alert(Dosya yüklenirken bir hata oluştu: ${error.message});
});
});
</code></pre>
Bu örnekte, bir elementinden seçilen dosya alınır. Ardından, bu dosya FormData nesnesine eklenir ve fetch isteğinin body‘si olarak gönderilir. FormData kullanıldığında, Content-Type başlığını manuel olarak ayarlamanıza gerek yoktur; tarayıcı bunu sizin için doğru şekilde yapar (genellikle multipart/form-data).
Dosya İndirme
Sunucudan bir dosya indirmek için de Fetch API kullanılabilir. Bu durumda, yanıtın gövdesini blob olarak almamız ve ardından bunu bir URL’ye dönüştürmemiz gerekir.
<pre><code class="language-javascript">
function dosyayiIndir(url, dosyaAdi) {
fetch(url)
.then(response => {
if (!response.ok) {
throw new Error(Dosya indirilemedi. Durum: ${response.status});
}
// Yanıtın içeriğini 'blob' olarak alıyoruz
return response.blob();
})
.then(blob => {
// Blob'u bir URL'ye dönüştürüyoruz
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = dosyaAdi; // İndirilecek dosyanın adı
document.body.appendChild(a);
a.click(); // Sahte bir tıklama ile indirmeyi başlatıyoruz
window.URL.revokeObjectURL(url); // Oluşturulan URL'yi temizliyoruz
a.remove(); // Link elementini DOM'dan kaldırıyoruz
console.log('Dosya başarıyla indirildi.');
})
.catch(error => {
console.error('Dosya indirme hatası:', error);
alert(Dosya indirilirken bir hata oluştu: ${error.message});
});
}
// Örnek kullanım:
// dosyayiIndir('https://api.example.com/files/rapor.pdf', 'aylik_rapor.pdf');
</code></pre>
Bu fonksiyon, belirli bir URL’den bir dosyayı indirir. Yanıtı response.blob() ile alır, bu bir ikili veri nesnesidir. Ardından window.URL.createObjectURL() ile bu blob’dan geçici bir URL oluşturulur. Bu URL, bir elementi aracılığıyla download özelliği ayarlanarak kullanılır. a.click() ile kullanıcı etkileşimi olmadan indirme işlemi tetiklenir. Son olarak, oluşturulan URL’nin belleği serbest bırakılır (revokeObjectURL).
Fetch API ile dosya işlemleri, modern web uygulamalarının daha zengin işlevsellikler sunmasına olanak tanır.
Fetch API ile İleri Düzey Teknikler ve İpuçları
Fetch API’nin temel kullanımlarını ve dosya işlemlerini ele aldık. Şimdi, daha deneyimli geliştiriciler için bazı ileri düzey tekniklere ve ipuçlarına göz atalım.
AbortController ile İstekleri İptal Etme
Büyük veya uzun süren ağ isteklerini iptal etmek, kullanıcı deneyimini iyileştirmek ve kaynakları verimli kullanmak için önemlidir. AbortController API’si ile bu mümkündür.
<pre><code class="language-javascript">
let controller = new AbortController();
let signal = controller.signal;
// İsteği başlat
const veriGetir = fetch('https://api.example.com/long-operation', {
signal: signal // Sinyali isteğe bağlıyoruz
})
.then(response => response.json())
.then(data => console.log('Uzun işlem tamamlandı:', data))
.catch(error => {
if (error.name === 'AbortError') {
console.log('İstek iptal edildi.');
} else {
console.error('İstek sırasında hata:', error);
}
});
// Belirli bir koşulda isteği iptal et (örneğin, kullanıcı başka bir sayfaya geçtiğinde)
function istegiIptalEt() {
controller.abort(); // İsteği iptal et
}
// Örnek: 10 saniye sonra isteği iptal et
setTimeout(() => {
istegiIptalEt();
}, 10000);
</code></pre>
AbortController oluşturulur, signal özelliği alınır ve fetch isteğine signal olarak iletilir. controller.abort() çağrıldığında, ilgili istek iptal edilir ve catch bloğunda AbortError yakalanır. Bu, kullanıcıların bir işlemden vazgeçmesi veya uygulamanın gereksiz ağ trafiği üretmesini engellemek için harikadır.
Servis Çalıştırıcıları (Service Workers) ile Fetch İsteklerini Yönetme
Servis çalıştırıcıları, arka planda çalışan ve ağ isteklerini yakalayıp işleyebilen proxy’lerdir. Fetch API ile servis çalıştırıcıları entegre edildiğinde, çevrimdışı destek, önbelleğe alma (caching) ve arka plan senkronizasyonu gibi gelişmiş özellikler sunulabilir.
Bir servis çalıştırıcısında, fetch olayını dinleyerek gelen istekleri yakalayabilir ve kendi yanıtlarınızı döndürebilir veya isteği orijinal hedefine yönlendirebilirsiniz.
<pre><code class="language-javascript">
// service-worker.js dosyasından bir örnek
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request) // Önbellekte isteği ara
.then(response => {
// Önbellekte varsa, onu döndür
if (response) {
return response;
}
// Yoksa, ağı kullanarak isteği yap
return fetch(event.request).then(networkResponse => {
// Ağıtaki yanıtı önbelleğe al
return caches.open('my-cache')
.then(cache => {
cache.put(event.request, networkResponse.clone());
return networkResponse;
});
});
})
.catch(error => {
console.error('Servis çalıştırıcı fetch hatası:', error);
// Hata durumunda alternatif bir yanıt döndür
return new Response('Çevrimdışı', { status: 503, statusText: 'Service Unavailable' });
})
);
});
</code></pre>
Bu örnek, bir isteğin önce önbellekte aranmasını, bulunamazsa ağdan alınmasını ve ardından önbelleğe kaydedilmesini gösterir. Bu, uygulamanızın çevrimdışı çalışmasını veya daha hızlı yanıt vermesini sağlayabilir.
Fetch API ile Timeout (Zaman Aşımı) Uygulama
Fetch API’nin doğrudan bir timeout seçeneği olmasa da, AbortController ile bir zaman aşımı mekanizması kolayca uygulanabilir.
<pre><code class="language-javascript">
function fetchWithTimeout(url, options = {}, timeout = 8000) { // Varsayılan zaman aşımı 8 saniye
let controller = new AbortController();
let signal = controller.signal;
const timeoutId = setTimeout(() => {
controller.abort();
}, timeout);
return fetch(url, {
...options,
signal: signal
})
.then(response => {
clearTimeout(timeoutId); // İstek başarılı olursa zamanlayıcıyı temizle
if (!response.ok) {
throw new Error(HTTP hatası! Durum: ${response.status});
}
return response.json();
})
.catch(error => {
clearTimeout(timeoutId); // Hata durumunda da zamanlayıcıyı temizle
if (error.name === 'AbortError') {
throw new Error(İstek zaman aşımına uğradı (${timeout / 1000} saniye).);
}
throw error; // Diğer hataları yay
});
}
// Kullanım:
fetchWithTimeout('https://api.example.com/slow-data', {}, 5000) // 5 saniye zaman aşımı
.then(data => console.log('Veri alındı:', data))
.catch(error => console.error('İşlem hatası:', error.message));
</code></pre>
Bu fetchWithTimeout fonksiyonu, belirtilen süre içinde yanıt gelmezse isteği iptal eder ve bir zaman aşımı hatası fırlatır. Bu, uygulamalarınızın yanıt vermeyen sunuculara takılıp kalmasını engeller.
Bu ileri düzey teknikler, Fetch API’yi daha karmaşık ve performans odaklı uygulamalarda kullanmanıza olanak tanır.
Sonuç ve Sıkça Sorulan Sorular
JavaScript Fetch API, modern web geliştiricileri için ağ isteklerini yönetmenin güçlü, esnek ve anlaşılır bir yolunu sunar. Basit GET ve POST isteklerinden dosya yükleme/indirme gibi daha karmaşık senaryolara kadar geniş bir kullanım alanına sahiptir. Promise tabanlı yapısı, asenkron kodunuzu daha okunabilir ve yönetilebilir hale getirirken, AbortController ve servis çalıştırıcıları gibi özellikler, uygulamalarınızın performansını ve kullanıcı deneyimini önemli ölçüde iyileştirmenize olanak tanır.
Fetch API’yi etkin bir şekilde kullanmak, RESTful API’lerle sorunsuz entegrasyon kurmanızı, dinamik içerik yüklemenizi ve kullanıcılarınıza zengin, etkileşimli deneyimler sunmanızı sağlar. Bu makalede ele aldığımız temel kavramlar, örnekler ve ileri düzey ipuçları, Fetch API ile projelerinize başlamanız veya mevcut projelerinizi geliştirmeniz için sağlam bir temel oluşturacaktır.
Sıkça Sorulan Sorular (SSS)
* Fetch API ile XMLHttpRequest arasındaki temel farklar nelerdir?
Fetch API, Promise tabanlıdır, bu da asenkron işlemleri yönetmeyi daha kolay hale getirir. Söz dizimi daha basittir ve XMLHttpRequest‘in olay tabanlı yapısına göre daha okunabilir bir kod sunar. Ayrıca, Fetch API daha modüler bir yapıya sahiptir ve hata yönetimi daha standarttır.
* Fetch API tüm tarayıcılarda destekleniyor mu?
Fetch API, modern tarayıcıların büyük çoğunluğu tarafından desteklenmektedir (Chrome, Firefox, Safari, Edge vb.). Ancak, Internet Explorer gibi eski tarayıcılar için polyfill’lere ihtiyaç duyulabilir. Genellikle, hedef kitlenizin kullandığı tarayıcıları göz önünde bulundurarak polyfill kullanıp kullanmayacağınıza karar verebilirsiniz.
* Fetch API ile PUT, DELETE gibi diğer HTTP yöntemlerini nasıl kullanabilirim?
PUT, DELETE, PATCH gibi diğer HTTP yöntemlerini kullanmak için fetch() fonksiyonuna ikinci argüman olarak bir obje geçirir ve method özelliğini ilgili değere ayarlarsınız. Örneğin:
<pre><code class="language-javascript">
fetch('/api/items/123', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Güncellenmiş Öğe' })
});
</code></pre>
* Fetch API ile nasıl JSON verisi gönderilir ve alınır?
JSON verisi göndermek için body özelliğini JSON.stringify() ile string’e dönüştürülmüş bir JavaScript objesi olarak ayarlayın ve Content-Type: application/json başlığını ekleyin. JSON verisi almak için ise response.json() metodunu kullanın. Bu metot, yanıt gövdesini ayrıştırır ve bir Promise döndürür.
* Fetch API isteğim neden CORS hatası veriyor?
CORS (Cross-Origin Resource Sharing) hatası, güvenlik nedeniyle tarayıcının farklı bir alan adından gelen isteklere izin vermemesinden kaynaklanır. Bu hatayı çözmek için, sunucu tarafında CORS başlıklarının (örneğin, Access-Control-Allow-Origin) doğru şekilde yapılandırılması gerekir. Tarayıcı, bu başlıkları kontrol ederek isteğin güvenli olup olmadığına karar verir.
