Fehlerbehandlung
Fangen Sie listingsapi-js-Fehlerklassen ab, lesen Sie Plattformfehlercodes und implementieren Sie Backoff unter Berücksichtigung von retryAfter.
Jeder Fehler, den das SDK auslöst, ist von ListingsAPIError abgeleitet. API-Fehler lösen APIError oder eine seiner Unterklassen aus, unabhängig davon, ob die Plattform sie über einen HTTP-Status außerhalb des 2xx-Bereichs oder im Antworttext einer HTTP-200-Antwort meldet. Netzwerkfehler (DNS-Fehler, abgelehnte Verbindungen, Zeitüberschreitungen) lösen APIConnectionError aus. Sie müssen weder success-Flags noch unverarbeitete Nutzdaten prüfen: Ein erfolgreich erfülltes Promise bedeutet, dass der Aufruf erfolgreich war.
Fehlerhierarchie
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 unknownAlle Klassen werden aus dem Stammverzeichnis des Pakets exportiert:
import {ListingsAPIError,APIError,AuthenticationError,PermissionDeniedError,NotFoundError,ValidationError,RateLimitError,InternalServerError,APIConnectionError,} from 'listingsapi-js';Eigenschaften von APIError
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);}}Fehler nach Typ abfangen
Authentifizierungsfehler
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.');}}Fehlende Ressourcen
import { NotFoundError } from 'listingsapi-js'; try {await client.fetchPremiumListings(99999999);} catch (error) {if (error instanceof NotFoundError) { console.error('Location not found.');}}Anfragelimits
RateLimitError.retryAfter enthält den Retry-After-Wert des Servers in Sekunden oder null, wenn der Header fehlt:
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');}}Validierungsfehler
Serverseitige Validierungsfehler enthalten die Fehlereinträge der Plattform:
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); }}}Fehler in HTTP-200-Antworten
Die Plattform meldet einige Fehler mit HTTP 200 und Fehlerdaten im Antworttext. Das SDK prüft jede Antwort und löst auch in diesen Fällen einen Fehler aus, sodass ein 200-Status niemals bedeutet: „Prüfen Sie den Antworttext selbst“:
Bei Schreibvorgängen (mit den Hilfsfunktionen POST und DELETE) prüft das SDK jedes Ergebnisobjekt in der Antwort; wenn eines davon success: false meldet oder errors[] enthält, löst es ValidationError aus, wobei statusCode auf 200 gesetzt ist.
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);}}Clientseitige Validierung in den post-Hilfsfunktionen
Die post-Hilfsfunktionen (createAnnouncement, createEvent, createOffer und bulkPublish) validieren ihre Nutzdaten lokal und lösen vor jedem Netzwerkaufruf ValidationError aus:
namedarf weder leer sein noch ausschließlich aus Leerraumzeichen bestehen, undlocationIdsdarf nicht leer sein.sitesmuss eine nicht leere Teilmenge ausGOOGLEundFACEBOOKsein.messageist erforderlich; wenn es sich um eine Zuordnung nach Website handelt, benötigt jede Zielwebsite einen Eintrag, der weder leer ist noch ausschließlich aus Leerraumzeichen besteht.ctaTypeundctaUrlmüssen zusammen angegeben werden, undctaTypemuss einen der WerteBOOK,ORDER,SHOP,LEARN_MORE,SIGN_UP,GET_OFFERhaben.createEventundcreateOffererfordern zusätzlichtitle.postType(beibulkPublish) muss einen der WerteANNOUNCEMENT,EVENT,OFFER,COVID19,PRODUCThaben.
Diese lokalen Fehler haben statusCode: null, woran Sie sie von einer serverseitigen Ablehnung unterscheiden können. Die systemnahe Methode createPost(body) sendet ihren unverarbeiteten Anfragetext ohne diese Prüfungen.
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}}Integrierte Wiederholungsversuche
Der Client wiederholt Anfragen bei 429- und 5xx-Antworten (unter Berücksichtigung des Retry-After-Headers) sowie bei Netzwerkfehlern selbstständig, standardmäßig zweimal. Fehler werden erst an Ihren Code weitergegeben, wenn diese Versuche ausgeschöpft sind. Informationen zu den Optionen maxRetries und timeout finden Sie unter Konfiguration.
Ein Backoff-Beispiel, das retryAfter berücksichtigt
Für lang laufende Aufgaben, die über die integrierten Wiederholungsversuche des Clients hinaus weiterlaufen sollen, führen Sie Aufrufe in einer Backoff-Schleife aus, die vorrangig die retryAfter-Angabe des Servers verwendet und andernfalls auf exponentiell steigende Wartezeiten zurückgreift:
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 }));Bei NotFoundError, ValidationError, AuthenticationError und PermissionDeniedError werden Anfragen bewusst nicht wiederholt: Eine Wiederholung dieser Anfragen kann ohne Änderung der Eingabe oder des Schlüssels nicht erfolgreich sein.
Netzwerkfehler und Zeitüberschreitungen
Alles, was den Eingang einer Antwort verhindert (DNS-Fehler, abgelehnte Verbindung oder Überschreitung des Zeitlimits für die jeweilige Anfrage), löst APIConnectionError aus. Das SDK gibt die nativen Fehler TypeError oder AbortError von fetch niemals weiter.
APIConnectionError bedeutet nicht, dass die Anfrage den Server nie erreicht hat. Bei einem DNS-Fehler oder einer abgelehnten Verbindung wurde die Anfrage zwar vor Erreichen der API gestoppt, aber eine Zeitüberschreitung gehört zur selben Fehlerklasse, und die Anfrage kann eingegangen und abgeschlossen worden sein, nachdem der Client bereits aufgegeben hat. Behandeln Sie diesen Fall als Ergebnis unbekannt: Einen Lesevorgang können Sie ohne Weiteres wiederholen; lesen Sie bei einem Schreibvorgang vor der Wiederholung den Datensatz erneut aus, da die API wiederholte Schreibvorgänge nicht erkennt.
Zeitlimits werden intern bei jedem Versuch mit AbortSignal.timeout durchgesetzt, standardmäßig mit 240000 ms, konfigurierbar über die Konstruktoroption timeout. Ein Versuch mit Zeitüberschreitung wird wie jeder andere Verbindungsfehler wiederholt; nur der letzte Fehler wird ausgelöst:
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);}}Weiterführende Ressourcen
- Konfiguration, die Optionen
timeoutundmaxRetries - Schnellstart, minimales Beispiel zur Fehlerbehandlung
- Anwendungsfälle, praxisnahe Fehlerbehandlung in vollständigen Skripten