Bu ders için video bulunmamaktadır.

Bu derse başlamak veya ilerlemenizi kaydetmek için lütfen giriş yapın veya kayıt olun.

Ders İçeriği

Giriş: Web'de Veri Alışverişi

Modern web uygulamaları, kullanıcı deneyimini iyileştirmek için sayfayı tamamen yenilemeden sunucudan veri alabilmeli ve sunucuya veri gönderebilmelidir. Bu tür eşzamansız veri alışverişi, web uygulamalarının daha hızlı, daha duyarlı ve daha etkileşimli olmasını sağlar.

Bu derste, JavaScript'te web sunucularıyla veri alışverişi yapmak için kullanılan iki temel yaklaşımı inceleyeceğiz:

  1. AJAX (Asynchronous JavaScript and XML): Sayfayı yenilemeden sunucuyla veri alışverişi yapmanın geleneksel yöntemi. XMLHttpRequest (XHR) nesnesi kullanılır.
  2. Fetch API: Modern tarayıcılarda sunulan, Promise tabanlı, daha temiz ve güçlü bir HTTP istekleri yapma yöntemi.

Bu teknolojiler, tek sayfa uygulamaları (SPA), dinamik içerik yükleme, form gönderimi, API entegrasyonu ve daha birçok modern web özelliği için temel oluşturur.

AJAX Nedir?

AJAX (Asynchronous JavaScript and XML), web sayfalarının arka planda veri alışverişi yapmasını sağlayan bir web geliştirme tekniğidir. AJAX, sayfayı tamamen yenilemeden sunucudan veri almanıza, veri göndermenize ve sayfanın belirli bölümlerini güncellemenize olanak tanır.

AJAX'ın adındaki "XML" kısmı, başlangıçta veri formatı olarak XML kullanıldığını gösterir, ancak günümüzde AJAX istekleri genellikle JSON, HTML, metin veya diğer formatları kullanır.

AJAX'ın temel bileşeni, XMLHttpRequest (XHR) nesnesidir. Bu nesne, JavaScript'in sunucuyla HTTP istekleri yapmasını sağlar.

XMLHttpRequest (XHR) Kullanımı

XHR nesnesi, AJAX isteklerini gerçekleştirmek için kullanılan geleneksel yöntemdir. Temel adımları şunlardır:

  1. XHR nesnesini oluşturmak
  2. İstek için olay dinleyicileri eklemek
  3. İsteği yapılandırmak (açmak)
  4. İsteği göndermek
  5. Yanıtı işlemek
xhr_get_request.js
// GET isteği örneği
function veriGetir() {
    // 1. XHR nesnesini oluştur
    const xhr = new XMLHttpRequest();
    
    // 2. Olay dinleyicileri ekle
    xhr.onreadystatechange = function() {
        // readyState 4: İstek tamamlandı ve yanıt hazır
        if (xhr.readyState === 4) {
            if (xhr.status === 200) {
                // Başarılı yanıt
                const data = JSON.parse(xhr.responseText);
                console.log('Veri başarıyla alındı:', data);
                // Veriyi işle...
            } else {
                // Hata durumu
                console.error('Hata oluştu:', xhr.status, xhr.statusText);
            }
        }
    };
    
    // İlerleme durumunu izleme (opsiyonel)
    xhr.onprogress = function(event) {
        if (event.lengthComputable) {
            const percentComplete = (event.loaded / event.total) * 100;
            console.log(`İlerleme: ${percentComplete.toFixed(2)}%`);
        }
    };
    
    // Hata durumu için (opsiyonel)
    xhr.onerror = function() {
        console.error('İstek sırasında bir hata oluştu.');
    };
    
    // 3. İsteği yapılandır (aç)
    xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true); // true = eşzamansız
    
    // İstek başlıkları ekle (opsiyonel)
    xhr.setRequestHeader('Content-Type', 'application/json');
    
    // 4. İsteği gönder
    xhr.send();
}

veriGetir();

POST İsteği ile Veri Gönderme

XHR ile sunucuya veri göndermek için POST, PUT veya diğer HTTP metodlarını kullanabilirsiniz:

xhr_post_request.js
// POST isteği örneği
function veriGonder() {
    const xhr = new XMLHttpRequest();
    
    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
            if (xhr.status === 201) { // 201 Created
                const response = JSON.parse(xhr.responseText);
                console.log('Veri başarıyla gönderildi:', response);
            } else {
                console.error('Hata oluştu:', xhr.status, xhr.statusText);
            }
        }
    };
    
    xhr.open('POST', 'https://jsonplaceholder.typicode.com/posts', true);
    
    // İstek başlıkları
    xhr.setRequestHeader('Content-Type', 'application/json');
    
    // Gönderilecek veri
    const data = {
        title: 'JavaScript AJAX Örneği',
        body: 'Bu bir POST isteği örneğidir.',
        userId: 1
    };
    
    // Veriyi JSON formatına dönüştür ve gönder
    xhr.send(JSON.stringify(data));
}

veriGonder();

XHR'nin Durumları (readyState)

XHR nesnesi, istek yaşam döngüsü boyunca farklı durumlardan geçer. readyState özelliği, bu durumları temsil eder:

  • 0 (UNSENT): XHR nesnesi oluşturuldu, ancak open() metodu henüz çağrılmadı.
  • 1 (OPENED): open() metodu çağrıldı.
  • 2 (HEADERS_RECEIVED): send() metodu çağrıldı ve başlıklar alındı.
  • 3 (LOADING): Yanıt yükleniyor (yanıtın bir kısmı alındı).
  • 4 (DONE): İşlem tamamlandı (başarılı veya başarısız).

Genellikle, readyState === 4 durumunu kontrol ederiz, çünkü bu, isteğin tamamlandığını ve yanıtın hazır olduğunu gösterir.

Fetch API

Fetch API, modern tarayıcılarda sunulan, HTTP istekleri yapmak için daha temiz ve güçlü bir arayüzdür. XMLHttpRequest'e göre birçok avantajı vardır:

  • Promise tabanlıdır, bu da daha temiz ve okunabilir kod yazmanızı sağlar.
  • Async/await ile kullanılabilir.
  • Daha basit ve anlaşılır bir API sunar.
  • İstek ve yanıt nesneleri için daha fazla kontrol sağlar.
  • Service Workers ile çalışabilir.

Temel Fetch Kullanımı

Fetch API'nin en temel kullanımı, bir URL'den veri almaktır:

fetch_basic.js
// Temel GET isteği
fetch('https://jsonplaceholder.typicode.com/posts/1')
    .then(response => {
        // İlk olarak yanıtın başarılı olup olmadığını kontrol et
        if (!response.ok) {
            throw new Error(`HTTP hata! Durum: ${response.status}`);
        }
        // Yanıtı JSON olarak ayrıştır
        return response.json();
    })
    .then(data => {
        console.log('Veri alındı:', data);
        // Veriyi işle...
    })
    .catch(error => {
        console.error('Fetch hatası:', error);
    });

// Async/await ile aynı istek
async function veriGetir() {
    try {
        const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
        
        if (!response.ok) {
            throw new Error(`HTTP hata! Durum: ${response.status}`);
        }
        
        const data = await response.json();
        console.log('Veri alındı (async/await):', data);
        return data;
    } catch (error) {
        console.error('Fetch hatası (async/await):', error);
        throw error;
    }
}

veriGetir();

Not: fetch() fonksiyonu, ağ hatası durumunda bir Promise reddi (rejection) döndürür, ancak HTTP hata durumları (404, 500 vb.) için Promise'ı reddetmez. Bu nedenle, response.ok özelliğini kontrol etmek önemlidir.

Fetch ile POST İsteği

Fetch API ile veri göndermek için, ikinci bir argüman olarak istek seçeneklerini belirtebilirsiniz:

fetch_post.js
// POST isteği
async function veriGonder() {
    const veri = {
        title: 'JavaScript Fetch API Örneği',
        body: 'Bu bir POST isteği örneğidir.',
        userId: 1
    };
    
    try {
        const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
            method: 'POST', // HTTP metodu
            headers: {
                'Content-Type': 'application/json', // İçerik türü
                // Diğer başlıklar...
            },
            body: JSON.stringify(veri) // Gönderilecek veri (JSON formatında)
        });
        
        if (!response.ok) {
            throw new Error(`HTTP hata! Durum: ${response.status}`);
        }
        
        const sonuc = await response.json();
        console.log('Veri başarıyla gönderildi:', sonuc);
        return sonuc;
    } catch (error) {
        console.error('Fetch hatası:', error);
        throw error;
    }
}

veriGonder();

Fetch İstek Seçenekleri

Fetch API, istek yapılandırması için birçok seçenek sunar:

  • method: HTTP metodu (GET, POST, PUT, DELETE, vb.)
  • headers: İstek başlıkları (Headers nesnesi veya düz nesne)
  • body: İstek gövdesi (String, FormData, Blob, vb.)
  • mode: CORS modu (cors, no-cors, same-origin)
  • credentials: Kimlik bilgilerinin nasıl gönderileceği (omit, same-origin, include)
  • cache: Önbellek davranışı (default, no-store, reload, no-cache, force-cache, only-if-cached)
  • redirect: Yönlendirme davranışı (follow, error, manual)
  • referrer: Referrer bilgisi
  • referrerPolicy: Referrer politikası
  • integrity: Bütünlük doğrulaması
  • keepalive: Sayfa kapatıldıktan sonra isteğin devam edip etmeyeceği
  • signal: İsteği iptal etmek için AbortSignal
fetch_options.js
// Gelişmiş fetch seçenekleri örneği
async function gelismisIstek() {
    // İstek iptal kontrolü için
    const controller = new AbortController();
    const signal = controller.signal;
    
    // 5 saniye sonra isteği iptal et
    setTimeout(() => {
        controller.abort();
        console.log('İstek iptal edildi!');
    }, 5000);
    
    try {
        const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': 'Bearer token123', // Örnek yetkilendirme başlığı
                'X-Custom-Header': 'CustomValue'
            },
            body: JSON.stringify({
                title: 'Gelişmiş Fetch Örneği',
                body: 'Bu bir gelişmiş fetch isteği örneğidir.',
                userId: 1
            }),
            mode: 'cors', // CORS modu
            credentials: 'include', // Çerezleri ve kimlik bilgilerini gönder
            cache: 'no-cache', // Önbellek davranışı
            redirect: 'follow', // Yönlendirmeleri takip et
            referrerPolicy: 'no-referrer', // Referrer bilgisi gönderme
            signal: signal // İptal sinyali
        });
        
        if (!response.ok) {
            throw new Error(`HTTP hata! Durum: ${response.status}`);
        }
        
        const data = await response.json();
        console.log('Veri alındı:', data);
        return data;
    } catch (error) {
        if (error.name === 'AbortError') {
            console.log('İstek kullanıcı tarafından iptal edildi');
        } else {
            console.error('Fetch hatası:', error);
        }
        throw error;
    }
}

gelismisIstek().catch(err => console.log('İşlem hatası:', err.message));

Yanıt İşleme

Fetch API, yanıtları işlemek için çeşitli metodlar sunar. Yanıt formatına bağlı olarak farklı metodlar kullanabilirsiniz:

Yanıt Formatları

  • response.json(): Yanıtı JSON olarak ayrıştırır ve bir Promise döndürür.
  • response.text(): Yanıtı metin olarak alır.
  • response.blob(): Yanıtı Blob (ikili veri) olarak alır (resimler, dosyalar vb. için).
  • response.formData(): Yanıtı FormData nesnesi olarak alır.
  • response.arrayBuffer(): Yanıtı ArrayBuffer olarak alır (ham ikili veri için).
fetch_response_formats.js
// JSON yanıtı
async function jsonVeriGetir() {
    const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
    const data = await response.json();
    console.log('JSON veri:', data);
    return data;
}

// Metin yanıtı
async function metinVeriGetir() {
    const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
    const text = await response.text();
    console.log('Metin veri:', text);
    return text;
}

// Resim (Blob) yanıtı
async function resimGetir() {
    const response = await fetch('https://via.placeholder.com/150');
    const blob = await response.blob();
    
    // Blob'u kullanarak bir URL oluştur
    const imageUrl = URL.createObjectURL(blob);
    
    // Resmi göster (örnek)
    const img = document.createElement('img');
    img.src = imageUrl;
    document.body.appendChild(img);
    
    return imageUrl;
}

// Yanıt başlıklarını ve durumunu kontrol etme
async function yanıtBilgileriniGetir() {
    const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
    
    console.log('Durum:', response.status, response.statusText);
    console.log('Başlıklar:');
    
    // Başlıkları döngüyle gezmek
    for (const [key, value] of response.headers) {
        console.log(`${key}: ${value}`);
    }
    
    // Belirli bir başlığı almak
    console.log('Content-Type:', response.headers.get('content-type'));
    
    // Diğer yanıt özellikleri
    console.log('URL:', response.url);
    console.log('Yönlendirildi mi:', response.redirected);
    console.log('Tür:', response.type); // basic, cors, error, opaque, opaqueredirect
    
    const data = await response.json();
    return data;
}

Form Verisi Gönderme

Web uygulamalarında, form verilerini sunucuya göndermek yaygın bir işlemdir. Fetch API ile form verilerini göndermenin birkaç yolu vardır:

JSON Olarak Form Verisi Gönderme

fetch_form_json.js
// Form verilerini JSON olarak gönderme
async function formGonder() {
    // Form verilerini bir nesne olarak topla
    const formVeri = {
        username: 'kullanici123',
        email: 'ornek@example.com',
        message: 'Merhaba, bu bir test mesajıdır.'
    };
    
    try {
        const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(formVeri)
        });
        
        if (!response.ok) {
            throw new Error(`HTTP hata! Durum: ${response.status}`);
        }
        
        const sonuc = await response.json();
        console.log('Form başarıyla gönderildi:', sonuc);
        return sonuc;
    } catch (error) {
        console.error('Form gönderme hatası:', error);
        throw error;
    }
}

FormData Nesnesi Kullanma

FormData nesnesi, form verilerini kolayca toplamak ve göndermek için kullanılabilir. Özellikle dosya yüklemeleri için kullanışlıdır.

fetch_formdata.js
// FormData kullanarak form gönderme
async function formDataGonder() {
    // HTML'de bir form olduğunu varsayalım
    // 
    //   
    //   
    //   Merhaba, bu bir test mesajıdır.
    //   
    // 
    
    // Form elementini seç
    const form = document.getElementById('userForm');
    
    // FormData nesnesi oluştur
    const formData = new FormData(form);
    
    // FormData'ya manuel olarak veri ekleyebilirsiniz
    formData.append('extraField', 'Ekstra veri');
    
    try {
        const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
            method: 'POST',
            // FormData kullanırken Content-Type başlığı otomatik olarak ayarlanır
            // multipart/form-data olarak ayarlanır ve sınır (boundary) eklenir
            body: formData
        });
        
        if (!response.ok) {
            throw new Error(`HTTP hata! Durum: ${response.status}`);
        }
        
        const sonuc = await response.json();
        console.log('Form başarıyla gönderildi:', sonuc);
        return sonuc;
    } catch (error) {
        console.error('Form gönderme hatası:', error);
        throw error;
    }
}

// FormData'yı manuel olarak oluşturma
async function manuelFormDataGonder() {
    const formData = new FormData();
    
    // Metin verileri ekle
    formData.append('username', 'kullanici123');
    formData.append('email', 'ornek@example.com');
    formData.append('message', 'Merhaba, bu bir test mesajıdır.');
    
    // Dosya ekleme (bir dosya seçici input'tan)
    const fileInput = document.querySelector('input[type="file"]');
    if (fileInput.files.length > 0) {
        formData.append('avatar', fileInput.files[0]);
    }
    
    // FormData içeriğini kontrol etme
    for (const pair of formData.entries()) {
        console.log(`${pair[0]}: ${pair[1]}`);
    }
    
    // Gönder
    const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
        method: 'POST',
        body: formData
    });
    
    const sonuc = await response.json();
    return sonuc;
}

Hata Yönetimi ve İstek İptali

Fetch API ile yapılan isteklerde hata yönetimi ve istek iptali önemli konulardır.

Hata Yönetimi

Fetch API'de hata yönetimi için dikkat edilmesi gereken iki durum vardır:

  1. Ağ Hataları: Fetch, ağ hatası durumunda Promise'ı reddeder (reject).
  2. HTTP Hata Durumları: Fetch, 404 veya 500 gibi HTTP hata durumlarında Promise'ı reddetmez. Bu nedenle, response.ok özelliğini kontrol etmelisiniz.
fetch_error_handling.js
// Kapsamlı hata yönetimi
async function veriGetirHataYonetimi() {
    try {
        const response = await fetch('https://jsonplaceholder.typicode.com/nonexistent');
        
        // HTTP durum kodunu kontrol et
        if (!response.ok) {
            // Hata mesajını ve durum kodunu içeren özel bir hata fırlat
            const errorMsg = `HTTP Hata! Durum: ${response.status}`;
            const error = new Error(errorMsg);
            error.status = response.status;
            error.response = response;
            throw error;
        }
        
        const data = await response.json();
        return data;
    } catch (error) {
        // Ağ hatası mı yoksa HTTP hatası mı olduğunu kontrol et
        if (error.status) {
            // HTTP hatası
            console.error(`HTTP Hatası: ${error.status}`);
            
            // Farklı hata durumlarını ele al
            switch (error.status) {
                case 404:
                    console.error('Kaynak bulunamadı!');
                    // Kullanıcıya uygun mesaj göster...
                    break;
                case 401:
                    console.error('Yetkilendirme hatası!');
                    // Kullanıcıyı giriş sayfasına yönlendir...
                    break;
                case 500:
                    console.error('Sunucu hatası!');
                    // Kullanıcıya sunucu hatası mesajı göster...
                    break;
                default:
                    console.error('Bilinmeyen hata!');
            }
        } else {
            // Ağ hatası veya diğer hatalar
            console.error('Ağ hatası veya başka bir hata:', error.message);
        }
        
        // Hatayı yeniden fırlat veya özel bir değer döndür
        throw error; // veya return { error: true, message: error.message };
    }
}

İstek İptali

Fetch API, AbortController ve AbortSignal arayüzleri ile istekleri iptal etme yeteneği sunar. Bu, uzun süren istekleri iptal etmek veya kullanıcı bir sayfadan ayrıldığında istekleri temizlemek için kullanışlıdır.

fetch_abort.js
// İstek iptali örneği
function istekIptalOrnek() {
    // AbortController oluştur
    const controller = new AbortController();
    const signal = controller.signal;
    
    // İptal butonunu dinle
    const iptalBtn = document.getElementById('iptalBtn');
    iptalBtn.addEventListener('click', () => {
        // İsteği iptal et
        controller.abort();
        console.log('İstek kullanıcı tarafından iptal edildi!');
    });
    
    // Zaman aşımı için iptal
    const timeout = setTimeout(() => {
        controller.abort();
        console.log('İstek zaman aşımı nedeniyle iptal edildi!');
    }, 5000); // 5 saniye sonra iptal et
    
    // Fetch isteği yap
    fetch('https://jsonplaceholder.typicode.com/photos', {
        signal: signal // İptal sinyalini ekle
    })
        .then(response => {
            clearTimeout(timeout); // Zaman aşımı zamanlayıcısını temizle
            return response.json();
        })
        .then(data => {
            console.log(`${data.length} fotoğraf alındı`);
        })
        .catch(err => {
            if (err.name === 'AbortError') {
                console.log('İstek iptal edildi');
            } else {
                console.error('Fetch hatası:', err);
            }
        });
}

// Async/await ile istek iptali
async function istekIptalAsync() {
    const controller = new AbortController();
    const signal = controller.signal;
    
    // 3 saniye sonra iptal et
    setTimeout(() => {
        controller.abort();
        console.log('İstek otomatik olarak iptal edildi');
    }, 3000);
    
    try {
        const response = await fetch('https://jsonplaceholder.typicode.com/photos', {
            signal: signal
        });
        
        const data = await response.json();
        console.log(`${data.length} fotoğraf alındı`);
    } catch (err) {
        if (err.name === 'AbortError') {
            console.log('İstek iptal edildi');
        } else {
            console.error('Fetch hatası:', err);
        }
    }
}

Alıştırmalar

  1. JSONPlaceholder API'sinden (https://jsonplaceholder.typicode.com/posts) tüm gönderileri çeken ve bunları bir HTML listesinde gösteren bir fonksiyon yazın.
  2. Bir kullanıcı ID'si alan ve o kullanıcının gönderilerini (https://jsonplaceholder.typicode.com/posts?userId=1) çeken bir fonksiyon yazın. Async/await kullanın ve hata yönetimini ekleyin.
  3. Bir form oluşturun ve form verilerini FormData kullanarak https://jsonplaceholder.typicode.com/posts adresine POST isteği ile gönderin.
  4. Bir istek yapın ve 3 saniye sonra otomatik olarak iptal eden bir fonksiyon yazın. İptal durumunu uygun şekilde ele alın.
  5. Paralel olarak birden fazla API isteği yapan (örneğin, kullanıcılar, gönderiler ve yorumlar) ve tüm sonuçları birleştiren bir fonksiyon yazın. Promise.all() kullanın.

Bu derste, web uygulamalarında veri alışverişi için kullanılan iki temel yaklaşımı inceledik:

  • AJAX (XMLHttpRequest):
    • Geleneksel yöntem, tüm tarayıcılarda desteklenir.
    • Callback tabanlı API, daha karmaşık kod yapısı.
    • readyState ve status kontrolleri gerektirir.
    • Olay dinleyicileri (onreadystatechangeonloadonerror vb.) kullanır.
  • Fetch API:
    • Modern, Promise tabanlı API, daha temiz kod yapısı.
    • Async/await ile kullanılabilir.
    • İstek ve yanıt nesneleri için daha fazla kontrol.
    • AbortController ile istek iptali desteği.
    • HTTP hata durumlarını manuel olarak kontrol etmek gerekir (response.ok).
    • Çeşitli yanıt formatları için metodlar (json()text()blob() vb.).

Modern web geliştirmede, Fetch API genellikle tercih edilen yöntemdir, çünkü daha temiz, daha okunabilir ve daha güçlü bir API sunar. Ancak, eski tarayıcıları desteklemeniz gerekiyorsa, XMLHttpRequest veya bir polyfill kullanmanız gerekebilir.

Bir sonraki derste, modern web uygulamalarında yaygın olarak kullanılan JavaScript modülleri ve modül sistemlerini inceleyeceğiz.