Hata yönetimi

listingsapi-js hata sınıflarını yakalayın, platform hata kodlarını okuyun ve retryAfter bilgisini dikkate alan yeniden deneme gecikmeleri uygulayın.

SDK'nın fırlattığı her hata ListingsAPIError sınıfından türetilir. API hataları, platform bunları ister 2xx dışında bir HTTP durum koduyla ister HTTP 200 yanıt gövdesinde bildirsin, APIError veya alt sınıflarından biri olarak fırlatılır. Ağ hataları (DNS hataları, reddedilen bağlantılar, zaman aşımları) APIConnectionError olarak fırlatılır. success bayraklarını veya ham yanıt verilerini incelemeniz gerekmez: başarıyla sonuçlanan bir promise, çağrının başarılı olduğu anlamına gelir.

Hata hiyerarşisi

Code
ListingsAPIError                 base class for everything the SDK throws├── APIError                     any failure reported by the API│   ├── AuthenticationError      401, or invalid-token error payloads│   ├── PermissionDeniedError    403, or permission error payloads│   ├── NotFoundError            404, resource not found│   ├── ValidationError          400/422, mutations reporting success=false│   │                            or errors[], and client-side payload checks│   ├── RateLimitError           429, carries retryAfter│   └── InternalServerError      5xx, retry a read; read back a write first└── APIConnectionError           no response arrived: outcome unknown

Tüm sınıflar paketin kökünden dışa aktarılır:

TypeScript
import {ListingsAPIError,APIError,AuthenticationError,PermissionDeniedError,NotFoundError,ValidationError,RateLimitError,InternalServerError,APIConnectionError,} from 'listingsapi-js';

APIError özellikleri

ÖzellikTürAçıklama
statusCodenumber | nullBaşarısız yanıtın HTTP durum kodu: 401, 429, 500 veya hata bir 200 yanıtının gövdesinde geldiğinde 200. İstemci tarafındaki doğrulama hataları için null.
codestring | nullPlatformun ilk hata kodu, e.g. API bir hata kodu gönderdiyse SY10005.
errorsApiErrorEntry[]{ code, message, context } biçimine dönüştürülmüş tüm hata girdileri.
responseBodystring | nullDize olarak ham yanıt gövdesi.
retryAfternumber | nullYalnızca RateLimitError için. Yeniden denemeden önce beklenecek saniye sayısı; Retry-After başlığından okunur veya başlık yoksa null olur.
messagestringSonuna hata girdileri (veya ham gövde) eklenmiş, okunabilir bir özet.
namestringSomut sınıfın adı, e.g. "RateLimitError".
TypeScript
import { ListingsAPI, APIError, APIConnectionError } from 'listingsapi-js'; const client = new ListingsAPI(); try {await client.fetchAllLocations({ first: 10 });} catch (error) {if (error instanceof APIError) {  console.error(error.statusCode);   // 401, 429, 500, or 200 for payload errors  console.error(error.code);         // first platform code, e.g. 'SY10005'  console.error(error.errors);       // [{ code, message, context }, ...]  console.error(error.responseBody); // raw body text} else if (error instanceof APIConnectionError) {  // No response arrived. A read is safe to retry; for a write, read the  // record back before repeating it.  console.error('No response from the API:', error.message);}}

Hataları türüne göre yakalama

Kimlik doğrulama hataları

TypeScript
import { AuthenticationError } from 'listingsapi-js'; try {await client.fetchAllLocations({ first: 1 });} catch (error) {if (error instanceof AuthenticationError) {  console.error('Invalid API key. Rotate it under API Keys in the dashboard.');}}

Bulunamayan kaynaklar

TypeScript
import { NotFoundError } from 'listingsapi-js'; try {await client.fetchPremiumListings(99999999);} catch (error) {if (error instanceof NotFoundError) {  console.error('Location not found.');}}

İstek hızı sınırları

RateLimitError.retryAfter, sunucunun Retry-After değerini saniye cinsinden içerir; başlık yoksa null değerini içerir:

TypeScript
import { RateLimitError } from 'listingsapi-js'; try {await client.fetchAllLocations({ first: 100 });} catch (error) {if (error instanceof RateLimitError) {  const waitSeconds = error.retryAfter ?? 5;  console.error('Rate limited, retry in ' + waitSeconds + 's');}}

Doğrulama hataları

Sunucu tarafındaki doğrulama hataları, platformun hata girdilerini içerir:

TypeScript
import { ValidationError } from 'listingsapi-js'; try {await client.updateLocation({ id: 16808, phone: 'not-a-phone-number' });} catch (error) {if (error instanceof ValidationError) {  for (const entry of error.errors) {    console.error((entry.code ?? 'unknown') + ': ' + entry.message);  }}}

HTTP 200 yanıtlarının içindeki hatalar

Platform bazı hataları HTTP 200 durum koduyla ve gövdede hata verileriyle bildirir. SDK her yanıtı inceler ve bu durumlarda da hata fırlatır; dolayısıyla 200 durum kodu hiçbir zaman "gövdeyi kendiniz kontrol edin" anlamına gelmez:

Yanıt verilerindeki hata göstergesiFırlatılan hata türü
SY90005 veya SY90001 kodunu içeren üst düzey errors[]AuthenticationError
SY90003 kodunu içeren üst düzey errors[]PermissionDeniedError
RATE_LIMITED kodunu içeren üst düzey errors[]RateLimitError
Diğer tüm üst düzey errors[] değerleriAPIError
errors[] veya success: false içeren yazma işlemi sonucuValidationError

Yazma işlemlerinde (POST ve DELETE yardımcı işlevleri), SDK yanıttaki her sonuç nesnesini kontrol eder; herhangi biri success: false bildirirse veya errors[] içerirse, statusCode değeri 200 olarak ayarlanmış bir ValidationError hatası fırlatır.

TypeScript
import { ValidationError } from 'listingsapi-js'; try {const result = await client.archiveLocations([16808]);console.log('Archived:', result);} catch (error) {if (error instanceof ValidationError) {  // The API answered 200 but rejected the mutation  console.error(error.statusCode); // 200  console.error(error.message);}}

Gönderi yardımcı işlevlerinde istemci tarafı doğrulama

Gönderi yardımcı işlevleri (createAnnouncement, createEvent, createOffer ve bulkPublish), gönderecekleri verileri yerel olarak doğrular ve herhangi bir ağ çağrısından önce ValidationError fırlatır:

  • name boş veya yalnızca boşluk karakterlerinden oluşan bir değer olmamalı, locationIds ise boş olmamalıdır.
  • sites, GOOGLE ve FACEBOOK değerlerinden oluşan kümenin boş olmayan bir alt kümesi olmalıdır.
  • message zorunludur; site bazında bir eşleme olduğunda, hedeflenen her site için boş olmayan ve yalnızca boşluk karakterlerinden oluşmayan bir girdi bulunmalıdır.
  • ctaType ve ctaUrl birlikte sağlanmalıdır ve ctaType şu değerlerden biri olmalıdır: BOOK, ORDER, SHOP, LEARN_MORE, SIGN_UP, GET_OFFER.
  • createEvent ve createOffer için ayrıca title gereklidir.
  • bulkPublish üzerindeki postType şu değerlerden biri olmalıdır: ANNOUNCEMENT, EVENT, OFFER, COVID19, PRODUCT.

Bu yerel hatalar statusCode: null içerir; bu sayede bunları sunucu tarafındaki bir ret yanıtından ayırt edebilirsiniz. Düşük seviyeli createPost(body) metodu, ham gövdesini bu kontrolleri yapmadan gönderir.

TypeScript
import { ListingsAPI, ValidationError } from 'listingsapi-js'; const client = new ListingsAPI(); try {await client.createAnnouncement({  name: 'Grand opening',  locationIds: [16808],  message: 'Acme Dental is now open in Midtown!',  ctaType: 'BOOK', // ctaUrl missing: throws before any request is sent});} catch (error) {if (error instanceof ValidationError && error.statusCode === null) {  console.error(error.message);  // Invalid post: ctaType and ctaUrl must be provided together}}

Yerleşik yeniden deneme mekanizması

İstemci, 429 ve 5xx yanıtlarında (Retry-After başlığını dikkate alarak) ve ağ hatalarında varsayılan olarak 2 kez yeniden dener. Hatalar kodunuza yalnızca bu denemeler tükendikten sonra ulaşır. maxRetries ve timeout seçenekleri için Yapılandırma bölümüne bakın.

retryAfter değerini dikkate alan bir bekleyerek yeniden deneme örneği

İstemcinin yerleşik yeniden denemeleri tükendikten sonra da devam etmesi gereken uzun süreli işler için çağrıları, öncelikle sunucunun retryAfter bilgisini kullanan ve bu bilgi yoksa üstel olarak artan bekleme süreleri uygulayan bir yeniden deneme döngüsüne alın:

backoff.ts
import {ListingsAPI,RateLimitError,InternalServerError,APIConnectionError,} from 'listingsapi-js'; const client = new ListingsAPI(); async function withBackoff<T>(fn: () => Promise<T>,maxAttempts = 5,): Promise<T> {for (let attempt = 1; attempt <= maxAttempts; attempt++) {  try {    return await fn();  } catch (err) {    const retryable =      err instanceof RateLimitError ||      err instanceof InternalServerError ||      err instanceof APIConnectionError;    if (!retryable || attempt === maxAttempts) throw err;     let delayMs = 500 * 2 ** (attempt - 1);    if (err instanceof RateLimitError && err.retryAfter !== null) {      delayMs = err.retryAfter * 1000;    }    await new Promise((resolve) => setTimeout(resolve, delayMs));  }}throw new Error('unreachable');} const page = await withBackoff(() => client.fetchAllLocations({ first: 25 }));

NotFoundError, ValidationError, AuthenticationError ve PermissionDeniedError durumlarında bilinçli olarak yeniden deneme yapılmaz: girdiyi veya anahtarı değiştirmeden bu istekleri tekrarlamak başarılı olamaz.

Ağ hataları ve zaman aşımları

Yanıtın ulaşmasını engelleyen her durum (DNS hatası, bağlantının reddedilmesi veya istek başına zaman aşımı süresinin dolması) APIConnectionError hatasının fırlatılmasına neden olur. SDK, fetch kaynaklı yerel TypeError veya AbortError hatalarını hiçbir zaman doğrudan dışarı aktarmaz.

APIConnectionError, isteğin sunucuya hiç ulaşmadığı anlamına gelmez. DNS hatasında veya bağlantı reddedildiğinde istek API'ye ulaşmadan durur, ancak zaman aşımı da aynı hata sınıfını kullanır ve istemci beklemeyi bıraktıktan sonra istek ulaşmış ve işlem tamamlanmış olabilir. Bunu sonucu bilinmeyen bir işlem olarak değerlendirin: okuma işlemini doğrudan yeniden deneyebilirsiniz; yazma işleminde ise API yinelenen yazma işlemlerini algılamadığından, işlemi tekrarlamadan önce kaydı yeniden okuyun.

Zaman aşımı her denemede dahili olarak AbortSignal.timeout ile uygulanır; varsayılan süre 240000 ms'dir ve timeout yapıcı seçeneğiyle yapılandırılabilir. Zaman aşımına uğrayan bir deneme, diğer bağlantı hatalarında olduğu gibi yeniden denenir; yalnızca son hata dışarıya fırlatılır:

TypeScript
import { ListingsAPI, APIConnectionError } from 'listingsapi-js'; const client = new ListingsAPI({ timeout: 15000 }); try {await client.fetchAllLocations({ first: 10 });} catch (error) {if (error instanceof APIConnectionError) {  console.error('Network failure or timeout:', error.message);}}