Webhooks ve Polling: Hangi API Entegrasyon Yöntemi Daha İyi?

Ashley Innocent

Ashley Innocent

20 March 2026

Webhooks ve Polling: Hangi API Entegrasyon Yöntemi Daha İyi?

Kurumsal Apidog

Şirket İçi Dağıtım

SSO & RBAC

SOC 2 Uyumlu

Apidog Enterprise'ı Keşfet

Kısaca: Yoklama (Polling) güncellemeleri periyodik olarak kontrol eder (basit ama verimsiz). Web kancaları (Webhooks) güncellemeleri gerçek zamanlı olarak iletir (verimli ama karmaşık). Nadir kontroller için yoklama, gerçek zamanlı güncellemeler için web kancaları kullanın. Modern PetstoreAPI, güvenilir web kancası teslimatı ile her iki modeli de destekler.

Farkı Anlamak

Yoklama (Polling): İstemci tekrar tekrar "Herhangi bir güncelleme var mı?" diye sorar. Web Kancaları (Webhooks): Sunucu, bir şey olduğunda "İşte bir güncelleme!" der.

Benzetme:

Yoklama (Polling): Nasıl Çalışır?

İstemci, değişiklikleri kontrol etmek için periyodik istekler yapar.

// Her 30 saniyede bir yokla
setInterval(async () => {
  const response = await fetch('https://petstoreapi.com/api/v1/orders/123');
  const order = await response.json();

  if (order.status === 'completed') {
    console.log('Sipariş tamamlandı!', order);
    clearInterval(pollInterval);
  }
}, 30000);

Yoklama modelleri:

Basit yoklama:

GET /api/v1/orders/123
# Mevcut sipariş durumunu döndürür

Koşullu yoklama (ETag):

GET /api/v1/orders/123
If-None-Match: "abc123"

# Değişmediyse 304 Not Modified döndürür
# Değiştiyse yeni verilerle 200 döndürür

Zamana dayalı yoklama (Since-based polling):

GET /api/v1/orders/123/events?since=1710331200
# Belirtilen zaman damgasından bu yana olayları döndürür

Web Kancaları (Webhooks): Nasıl Çalışır?

Sunucu, olaylar meydana geldiğinde uç noktanıza bir HTTP POST isteği gönderir.

Kurulum akışı:

// 1. Web kancası uç noktasını kaydet
POST /api/v1/webhooks
{
  "url": "https://myapp.com/webhooks/petstore",
  "events": ["order.created", "order.completed"],
  "secret": "whsec_abc123"
}

// 2. Sunucu, olay meydana geldiğinde web kancasını gönderir
POST https://myapp.com/webhooks/petstore
{
  "id": "evt_123",
  "type": "order.completed",
  "created": 1710331200,
  "data": {
    "orderId": "123",
    "status": "completed",
    "completedAt": "2024-01-01T12:00:00Z"
  }
}

// 3. Web kancasını doğrula ve işle
// 200 OK ile yanıt ver

Yoklama (Polling) Ne Zaman Kullanılmalı?

Şunlar için iyidir:

Örnekler:

Yoklama şu durumlarda uygundur:

Web Kancaları (Webhooks) Ne Zaman Kullanılmalı?

Şunlar için iyidir:

Örnekler:

Web kancaları şu durumlarda daha iyidir:

Karşılaştırma Tablosu

Faktör Yoklama (Polling) Web Kancaları (Webhooks)
Gecikme Yoklama aralığına kadar Gerçek zamanlı
Sunucu yükü Yüksek (çok sayıda boş istek) Düşük (sadece gerçek olaylar)
Karmaşıklık Basit Karmaşık
Güvenilirlik Yüksek (istemci yeniden denemeyi kontrol eder) Orta (yeniden deneme mantığı gerekir)
Kurulum Yok Uç nokta kaydı
Güvenlik duvarı sorunları Yok (yalnızca giden) Beyaz listeye alma gerekebilir
Maliyet Daha yüksek (daha fazla istek) Daha düşük (daha az istek)
En iyi kullanım Sık olmayan kontroller Gerçek zamanlı güncellemeler

Yoklama (Polling) Uygulaması

Temel Yoklama

async function pollOrderStatus(orderId, callback) {
  let lastStatus = null;

  const poll = async () => {
    try {
      const response = await fetch(`https://petstoreapi.com/api/v1/orders/${orderId}`);
      const order = await response.json();

      // Yalnızca durum değişirse geri çağır
      if (order.status !== lastStatus) {
        lastStatus = order.status;
        callback(order);
      }

      // Terminal duruma ulaştığında yoklamayı durdur
      if (['completed', 'cancelled'].includes(order.status)) {
        return;
      }

      // Yoklamaya devam et
      setTimeout(poll, 5000);
    } catch (error) {
      console.error('Yoklama hatası:', error);
      setTimeout(poll, 30000); // Hatada bekleme süresini uzat
    }
  };

  poll();
}

// Kullanım
pollOrderStatus('order-123', (order) => {
  console.log(`Sipariş durumu: ${order.status}`);
});

Akıllı Yoklama (Üstel Geri Çekilme)

async function smartPoll(url, callback, options = {}) {
  const {
    maxRetries = 10,
    initialInterval = 1000,
    maxInterval = 60000,
    stopCondition = () => false
  } = options;

  let retries = 0;
  let interval = initialInterval;
  let lastData = null;

  const poll = async () => {
    try {
      const response = await fetch(url);
      const data = await response.json();

      // Veriler değiştiyse geri çağır
      if (JSON.stringify(data) !== JSON.stringify(lastData)) {
        lastData = data;
        callback(data);
      }

      // Koşul karşılanırsa durdur
      if (stopCondition(data)) {
        return;
      }

      // Başarılı istekte aralığı sıfırla
      interval = initialInterval;

    } catch (error) {
      retries++;
      if (retries >= maxRetries) {
        throw new Error('Maksimum yeniden deneme aşıldı');
      }
    }

    // Üstel geri çekilme ile sonraki yoklamayı planla
    setTimeout(poll, interval);
    interval = Math.min(interval * 2, maxInterval);
  };

  poll();
}

// Kullanım: Tamamlanana kadar siparişi yokla
smartPoll('https://petstoreapi.com/api/v1/orders/123',
  (order) => console.log('Sipariş:', order),
  {
    stopCondition: (order) => ['completed', 'cancelled'].includes(order.status),
    initialInterval: 2000,
    maxInterval: 30000
  }
);

ETag ile Yoklama

async function pollWithEtag(url, callback) {
  let etag = null;

  const poll = async () => {
    const headers = {};
    if (etag) {
      headers['If-None-Match'] = etag;
    }

    const response = await fetch(url, { headers });

    if (response.status === 304) {
      // Değişmedi, yoklamaya devam et
      setTimeout(poll, 30000);
      return;
    }

    const data = await response.json();
    etag = response.headers.get('etag');

    callback(data);
    setTimeout(poll, 30000);
  };

  poll();
}

Web Kancaları (Webhooks) Uygulaması

Web Kancalarını Kaydetme

// Web kancası uç noktasını kaydet
async function registerWebhook(url, events) {
  const response = await fetch('https://petstoreapi.com/api/v1/webhooks', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${API_KEY}`
    },
    body: JSON.stringify({
      url,
      events,
      secret: generateSecret()
    })
  });

  return response.json();
}

function generateSecret() {
  return 'whsec_' + crypto.randomBytes(32).toString('hex');
}

Web Kancalarını Alma

const express = require('express');
const crypto = require('crypto');
const app = express();

// İmza doğrulaması için ham gövde ayrıştırıcı
app.use('/webhooks', express.raw({ type: 'application/json' }));

app.post('/webhooks/petstore', async (req, res) => {
  const signature = req.headers['x-petstore-signature'];
  const body = req.body;

  // İmzayı doğrula
  const isValid = verifySignature(body, signature, process.env.WEBHOOK_SECRET);

  if (!isValid) {
    return res.status(401).json({ error: 'Geçersiz imza' });
  }

  const event = JSON.parse(body.toString());

  // Olayı işle
  switch (event.type) {
    case 'order.created':
      await handleOrderCreated(event.data);
      break;
    case 'order.completed':
      await handleOrderCompleted(event.data);
      break;
    case 'order.cancelled':
      await handleOrderCancelled(event.data);
      break;
  }

  // Alındığını onayla
  res.status(200).json({ received: true });
});

function verifySignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

Yerel Olarak Web Kancalarını Test Etme

# Yerel uç noktayı açığa çıkarmak için ngrok kullanın
ngrok http 3000

# ngrok URL'sini web kancası uç noktası olarak kaydet
curl -X POST https://petstoreapi.com/api/v1/webhooks \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "url": "https://abc123.ngrok.io/webhooks/petstore",
    "events": ["order.created", "order.completed"]
  }'

Güvenilir Web Kancası Teslimatı

Web kancaları başarısız olabilir. Yeniden deneme mantığı uygulayın.

Gönderici Tarafı (Sunucu)

// Teslimat için web kancalarını sıraya al
const webhookQueue = [];

async function sendWebhook(event) {
  const webhooks = await db.webhooks.findMany({
    where: { events: { contains: event.type } }
  });

  for (const webhook of webhooks) {
    webhookQueue.push({
      webhook,
      event,
      attempts: 0,
      nextAttempt: Date.now()
    });
  }

  processQueue();
}

async function processQueue() {
  const now = Date.now();

  for (const item of webhookQueue) {
    if (item.nextAttempt > now) continue;

    try {
      await deliverWebhook(item);
      // Başarılı olursa sıradan kaldır
      webhookQueue.splice(webhookQueue.indexOf(item), 1);
    } catch (error) {
      // Üstel geri çekilmeyle yeniden denemeyi planla
      item.attempts++;
      item.nextAttempt = now + getBackoff(item.attempts);

      if (item.attempts >= 5) {
        // 5 denemeden sonra başarısız olarak işaretle
        await markWebhookFailed(item);
        webhookQueue.splice(webhookQueue.indexOf(item), 1);
      }
    }
  }

  setTimeout(processQueue, 5000);
}

function getBackoff(attempt) {
  // 1dk, 5dk, 15dk, 1sa, 4sa
  const delays = [60000, 300000, 900000, 3600000, 14400000];
  return delays[attempt - 1] || delays[delays.length - 1];
}

async function deliverWebhook({ webhook, event }) {
  const signature = generateSignature(event, webhook.secret);

  const response = await fetch(webhook.url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Petstore-Signature': signature,
      'X-Petstore-Event': event.type
    },
    body: JSON.stringify(event),
    timeout: 10000
  });

  if (!response.ok) {
    throw new Error(`HTTP ${response.status}`);
  }
}

Alıcı Tarafı (İstemci)

// Idempotent web kancası işleme
const processedEvents = new Set();

app.post('/webhooks/petstore', async (req, res) => {
  const event = JSON.parse(req.body.toString());

  // Zaten işlenmişse atla (idempotency)
  if (processedEvents.has(event.id)) {
    return res.status(200).json({ received: true });
  }

  try {
    await processEvent(event);
    processedEvents.add(event.id);

    // Eski olay kimliklerini temizle (son 1000'i tut)
    if (processedEvents.size > 1000) {
      const arr = Array.from(processedEvents);
      arr.slice(0, arr.length - 1000).forEach(id => processedEvents.delete(id));
    }

    res.status(200).json({ received: true });
  } catch (error) {
    console.error('Web kancası işleme hatası:', error);
    // Yeniden denemeyi tetiklemek için 5xx döndür
    res.status(500).json({ error: 'İşleme başarısız oldu' });
  }
});

async function processEvent(event) {
  // Olayı işle
  switch (event.type) {
    case 'order.created':
      await handleOrderCreated(event.data);
      break;
    // ... diğer olayları işle
  }
}

Hibrit Yaklaşım

Kritik güncellemeler için hem yoklama hem de web kancalarını kullanın.

class OrderMonitor {
  constructor(orderId, callback) {
    this.orderId = orderId;
    this.callback = callback;
    this.pollInterval = null;
  }

  async start() {
    // Anında geri bildirim için yoklama ile başla
    this.startPolling();

    // Gerçek zamanlı güncelleme için web kancasını kaydet
    await this.registerWebhook();
  }

  startPolling() {
    this.pollInterval = setInterval(async () => {
      const order = await this.fetchOrder();
      this.callback(order);

      if (['completed', 'cancelled'].includes(order.status)) {
        this.stop();
      }
    }, 10000);
  }

  async registerWebhook() {
    const response = await fetch('https://petstoreapi.com/api/v1/webhooks', {
      method: 'POST',
      headers: { 'Authorization': `Bearer ${TOKEN}` },
      body: JSON.stringify({
        url: 'https://myapp.com/webhooks/petstore',
        events: [`order.${this.orderId}`],
        oneTime: true // İlk teslimattan sonra otomatik sil
      })
    });

    this.webhookId = (await response.json()).id;
  }

  stop() {
    if (this.pollInterval) {
      clearInterval(this.pollInterval);
    }
    if (this.webhookId) {
      fetch(`https://petstoreapi.com/api/v1/webhooks/${this.webhookId}`, {
        method: 'DELETE'
      });
    }
  }
}

Sıkça Sorulan Sorular

S: Ne sıklıkla yoklama yapmalıyım?Aciliyetine bağlıdır. Gerçek zamanlıya yakın durumlar için 30 saniye. Acil olmayan durumlar için 5 dakika. Güncelliği sunucu yüküyle dengeleyin.

S: Web kancası uç noktam kapalıysa ne olur?İyi web kancası sağlayıcıları, üstel geri çekilme ile yeniden dener. Yinelenen teslimatları yönetmek için idempotency (tekrarlanan işlemlerin aynı sonucu vermesi) uygulayın.

S: Web kancalarını nasıl güvence altına alırım?Paylaşılan gizli anahtarları kullanarak imzaları doğrulayın. Yalnızca HTTPS kullanın. Olay verilerini doğrulayın.

S: Web kancalarını geçmiş veriler için kullanabilir miyim?Hayır. Web kancaları yalnızca yeni olaylar içindir. Geçmiş veriler için yoklama veya toplu API'leri kullanın.

S: Mobil uygulamalar için yoklama mı yoksa web kancaları mı kullanmalıyım?Yoklama mobil için daha basittir. Web kancaları, aracı olarak anlık bildirimler gerektirir.

S: Web kancası sorunlarını nasıl ayıklayabilirim?Test için webhook.site gibi araçları kullanın. Tüm web kancası teslimatlarını günlüğe kaydedin. API'nizde web kancası olay geçmişi sağlayın.

Modern PetstoreAPI hem yoklamayı hem de web kancalarını destekler. Uygulama detayları için web kancaları kılavuzuna bakın. Web kancası entegrasyonlarını Apidog ile test edin.

API Tasarım-Öncelikli Yaklaşımı Apidog'da Uygulayın

API'leri oluşturmanın ve kullanmanın daha kolay yolunu keşfedin