- Bir HTTP isteğini ve yanıtını açıklamak: metot, URL, başlıklar, gövde, durum kodu
fetchile GET ve POST istekleri göndermek, JSON okumak, HTTP ve ağ hatalarını doğru işlemek- Sağlam asenkron kalıplar kurmak: zaman aşımı, yeniden deneme, paralel istekler ve
URLSearchParams
Bir uygulamadaki hava tahmini, döviz kurları, sosyal ağdaki akış; hepsi sunuculardan bir API aracılığıyla gelir. Kodun bir HTTP isteği gönderir, sunucu da verilerle, genellikle JSON ile yanıt verir. fetch, tarayıcılarda ve Node.js'te (18. sürümden beri) bunun için hazır bulunan modern araçtır.
Bir dakikada HTTP
Bir istek; metot, URL, başlıklar (headers) ve bazen bir gövdeden (body) oluşur. Yanıtta bir durum kodu, başlıklar ve gövde bulunur. Durum kodunun ilk rakamı anlamı verir: 2xx başarı, 3xx yönlendirme, 4xx istemci hatası (hatalı istek), 5xx sunucu hatası.
POST /api/orders HTTP/1.1
Host: shop.example.com
Content-Type: application/json
Authorization: Bearer <token>
{"productId": 7, "quantity": 2}
HTTP/1.1 201 Created
Content-Type: application/json
{"id": 1043, "productId": 7, "quantity": 2, "status": "new"}Bir API kurma üslubu: veriler kendi URL'leri olan kaynaklardır (/users, /users/42), işlemler ise HTTP metotlarıyla ifade edilir. Her istek bağımsızdır (sunucu bir öncekini “hatırlamaz”) ve veriler genellikle JSON olarak taşınır.
| Metot | Anlamı | Örnek ve başarılı yanıt |
|---|---|---|
| GET | okumak | GET /users/42 → 200 OK |
| POST | oluşturmak | POST /orders → 201 Created |
| PUT / PATCH | tamamen / kısmen güncellemek | PATCH /users/42 → 200 OK |
| DELETE | silmek | DELETE /orders/1043 → 204 No Content |
fetch ile GET
fetch(url), bir Response nesnesiyle tamamlanan bir Promise döndürür. İş iki adımdır: önce yanıtı beklersin (başlıklar gelir), sonra gövdeyi response.json() ile okursun; bu da bir Promise'tir. Önemli nokta: fetch yalnızca bir ağ hatasında (internet yok, bilinmeyen alan adı, CORS) reddedilir. 404 ve 500 yanıtları da “başarıyla gelir”; bu yüzden her zaman response.ok'u (durum 200–299) kontrol et.
async function getUser(id) {
const response = await fetch(`https://api.example.com/users/${id}`);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
}
try {
const user = await getUser(42);
console.log(user.name, user.city);
await getUser(999999);
} catch (error) {
console.log('Request failed:', error.message);
}Aysel Baku Request failed: HTTP 404
api.example.com temsilî bir adrestir: gerçek bir API'de alan adları farklı olur. Bu sayfadaki çalıştırıcı gerçek istek göndermez; bu yüzden aşağıda sunucuyu taklit edeceğiz.Bir Response nesnesi doğrudan JavaScript'te oluşturulabilir. Bu, sunucuyu taklit edip internetsiz alıştırma yapmanı sağlar: fakeFetch tıpkı gerçek fetch gibi bir Response döndürür ve kodun farkı anlamaz. Testlerde de tam olarak böyle yapılır.
const db = { 42: { id: 42, name: 'Aysel', city: 'Baku' } };
async function fakeFetch(url) {
await new Promise((resolve) => setTimeout(resolve, 50));
const id = Number(url.split('/').pop());
const user = db[id];
return new Response(JSON.stringify(user ?? { error: 'Not found' }), {
status: user ? 200 : 404,
headers: { 'Content-Type': 'application/json' },
});
}
for (const id of [42, 7]) {
const response = await fakeFetch(`/api/users/${id}`);
console.log(response.status, response.ok, response.headers.get('content-type'));
console.log(await response.json());
}▸ Beklenen çıktı
200 true application/json
{ id: 42, name: 'Aysel', city: 'Baku' }
404 false application/json
{ error: 'Not found' }POST, başlıklar ve hatalar
Veri göndermek için fetch'e ikinci argüman olarak bir seçenekler nesnesi ver: method, headers ve body. Gövde metin olmalıdır; bu yüzden nesne JSON.stringify ile string'e çevrilir, Content-Type: application/json başlığı ise sunucuya biçimi bildirir. Giriş gerektiren API'ler genellikle bir Authorization: Bearer <token> başlığı bekler.
async function createOrder(order, token) {
const response = await fetch('https://api.example.com/orders', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify(order),
});
if (response.status === 401) throw new Error('Please log in again');
if (!response.ok) throw new Error(`Server error ${response.status}`);
return response.json();
}
const saved = await createOrder({ productId: 7, quantity: 2 }, token);
console.log('Created order', saved.id, saved.status);Created order 1043 new
Sağlam asenkron kalıplar
Gerçek ağ yavaş ve güvenilmezdir. Dört alışkanlık yardımcı olur: sorgu parametrelerini URL ve URLSearchParams ile kur (özel karakterler otomatik kodlanır); bağımsız istekleri Promise.all ile paralel gönder; bir süre sınırı koy — fetch(url, { signal: AbortSignal.timeout(8000) }), 8 saniye sonra isteği TimeoutError ile iptal eder; geçici hatalarda (5xx, 429) beklemeyi artırarak yeniden dene.
const url = new URL('https://api.example.com/search');
url.searchParams.set('q', 'plov & dolma');
url.searchParams.set('city', 'Baku');
url.searchParams.set('page', 2);
console.log(url.toString());
console.log(url.searchParams.get('q'));
console.log(Object.fromEntries(url.searchParams));▸ Beklenen çıktı
https://api.example.com/search?q=plov+%26+dolma&city=Baku&page=2
plov & dolma
{ q: 'plov & dolma', city: 'Baku', page: '2' }?q=plov & dolma isteği bozardı: & yeni bir parametre sanılırdı. URLSearchParams onu %26 olarak kodlar.function slowServer(ms, signal) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => resolve('data'), ms);
signal.addEventListener('abort', () => {
clearTimeout(timer);
reject(new DOMException('Request took too long', 'TimeoutError'));
});
});
}
async function withTimeout(ms, limit) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), limit);
try {
return await slowServer(ms, controller.signal);
} catch (error) {
return `failed: ${error.name}`;
} finally {
clearTimeout(timer);
}
}
console.log(await withTimeout(50, 200));
console.log(await withTimeout(500, 200));▸ Beklenen çıktı
data failed: TimeoutError
AbortController bir iptal sinyali oluşturur; gerçek fetch bu signal'ı kabul eder. AbortSignal.timeout(ms) aynı işi tek satırda yapar.getJSON(url) yardımcısını yaz: fakeFetch(url)'i çağırsın, yanıt başarılı değilse HTTP <status> mesajlı bir hata fırlatsın, başarılıysa ayrıştırılmış JSON'u döndürsün.
const products = { 1: { id: 1, title: 'Notebook', price: 5 } };
async function fakeFetch(url) {
const id = Number(url.split('/').pop());
const product = products[id];
return new Response(JSON.stringify(product ?? { error: 'Not found' }), {
status: product ? 200 : 404,
headers: { 'Content-Type': 'application/json' },
});
}
async function getJSON(url) {
// call fakeFetch, check response.ok, return the JSON
}
for (const url of ['/api/products/1', '/api/products/99']) {
try {
console.log(await getJSON(url));
} catch (error) {
console.log('Error:', error.message);
}
}▸ Beklenen çıktı
{ id: 1, title: 'Notebook', price: 5 }
Error: HTTP 404flakyFetch ilk iki seferde 503 döndürür. fetchWithRetry(url, retries) fonksiyonunu yaz: her başarısız denemeden sonra Attempt N: 503 yazdırsın; 5xx hatasında 100, sonra 200 ms (her seferinde iki katı) bekleyip yeniden denesin; retries hakkı bitince ya da 4xx gelince HTTP <status> hatası fırlatsın.
let calls = 0;
async function flakyFetch(url) {
calls++;
const ok = calls >= 3;
return new Response(JSON.stringify(ok ? { rates: { USD: 1.7 } } : {}), { status: ok ? 200 : 503 });
}
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function fetchWithRetry(url, retries) {
// only one attempt for now: add retries with a growing delay
const response = await flakyFetch(url);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
}
const data = await fetchWithRetry('/api/rates', 3);
console.log('Rates:', data.rates);▸ Beklenen çıktı
Attempt 1: 503
Attempt 2: 503
Rates: { USD: 1.7 }Önemli noktalar
- HTTP: istek = metot + URL + başlıklar + gövde; yanıt = durum + başlıklar + gövde. 2xx başarı, 4xx istemci hatası, 5xx sunucu hatası.
- REST: kaynaklar URL'lerde bulunur, işlemler metotlarla yapılır: GET okur, POST oluşturur, PUT/PATCH günceller, DELETE siler.
fetchyalnızca ağ hatalarında reddedilir; her zamanresponse.ok'u kontrol et ve gövdeyiawait response.json()ile bir kez oku.- POST için
method, birContent-Type: application/jsonbaşlığı vebody: JSON.stringify(data)gönder. - Sağlamlık: süre sınırı (
AbortSignal.timeout), geçici 5xx hatalarında yeniden deneme, paralel istekler içinPromise.allve parametreler içinURLSearchParams.
Kendini test et
10 soru. Her doğru cevap XP kazandırır.
fetch gönderiliyor. Ne olur?