Penanganan Error
Tangani kelas error listingsapi-js, baca kode error platform, dan terapkan penundaan percobaan ulang yang memperhitungkan retryAfter.
Setiap kesalahan yang dilempar SDK merupakan turunan dari ListingsAPIError. Kegagalan API melempar APIError atau salah satu subkelasnya, baik ketika platform melaporkannya sebagai status HTTP non-2xx maupun di dalam isi respons HTTP 200. Kegagalan jaringan (kesalahan DNS, koneksi ditolak, batas waktu terlampaui) melempar APIConnectionError. Anda tidak perlu memeriksa penanda success atau payload mentah: promise yang terpenuhi berarti pemanggilan berhasil.
Hierarki kesalahan
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 unknownSemua kelas diekspor dari akar paket:
import {ListingsAPIError,APIError,AuthenticationError,PermissionDeniedError,NotFoundError,ValidationError,RateLimitError,InternalServerError,APIConnectionError,} from 'listingsapi-js';Properti 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);}}Menangkap kesalahan berdasarkan tipe
Kegagalan autentikasi
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.');}}Sumber daya yang tidak ditemukan
import { NotFoundError } from 'listingsapi-js'; try {await client.fetchPremiumListings(99999999);} catch (error) {if (error instanceof NotFoundError) { console.error('Location not found.');}}Batas laju permintaan
RateLimitError.retryAfter menyimpan nilai Retry-After dari server dalam detik, atau null jika header tersebut tidak ada:
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');}}Kegagalan validasi
Kegagalan validasi di sisi server menyertakan entri kesalahan dari platform:
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); }}}Kesalahan di dalam respons HTTP 200
Platform melaporkan beberapa kegagalan dengan HTTP 200 dan payload kesalahan di dalam isi respons. SDK memeriksa setiap respons dan juga melempar kesalahan untuk kegagalan tersebut, sehingga status 200 tidak pernah berarti "periksa sendiri isi responsnya":
Untuk operasi penulisan (fungsi pembantu POST dan DELETE), SDK memeriksa setiap objek hasil dalam respons; jika ada yang melaporkan success: false atau menyertakan errors[], SDK melempar ValidationError dengan statusCode diatur ke 200.
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);}}Validasi di sisi klien pada fungsi pembantu post
Fungsi pembantu post (createAnnouncement, createEvent, createOffer, dan bulkPublish) memvalidasi payload secara lokal dan melempar ValidationError sebelum melakukan pemanggilan jaringan apa pun:
nametidak boleh kosong atau hanya berisi spasi, danlocationIdstidak boleh kosong.sitesharus berupa himpunan bagian yang tidak kosong dariGOOGLEdanFACEBOOK.messagewajib diisi; jika berupa pemetaan per situs, setiap situs yang ditargetkan harus memiliki entri yang tidak kosong dan tidak hanya berisi spasi.ctaTypedanctaUrlharus diberikan bersamaan, danctaTypeharus berupa salah satu dariBOOK,ORDER,SHOP,LEARN_MORE,SIGN_UP,GET_OFFER.createEventdancreateOfferjuga memerlukantitle.postType(padabulkPublish) harus berupa salah satu dariANNOUNCEMENT,EVENT,OFFER,COVID19,PRODUCT.
Kesalahan lokal ini memiliki statusCode: null, yang memungkinkan Anda membedakannya dari penolakan di sisi server. Metode tingkat rendah createPost(body) mengirim isi permintaan mentah tanpa pemeriksaan ini.
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}}Percobaan ulang bawaan
Klien secara otomatis mencoba ulang respons 429 dan 5xx (dengan mematuhi header Retry-After) serta kegagalan jaringan, secara default sebanyak 2 kali. Kesalahan baru diteruskan ke kode Anda setelah semua percobaan tersebut habis. Lihat Konfigurasi untuk opsi maxRetries dan timeout.
Contoh penerapan jeda percobaan ulang yang memperhitungkan retryAfter
Untuk tugas berdurasi panjang yang perlu terus berjalan setelah percobaan ulang bawaan klien habis, bungkus pemanggilan dalam perulangan dengan jeda yang mengutamakan petunjuk retryAfter dari server dan menggunakan jeda eksponensial jika petunjuk tersebut tidak tersedia:
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, dan PermissionDeniedError sengaja tidak dicoba ulang: mengulangi permintaan tersebut tidak akan berhasil tanpa mengubah masukan atau kunci.
Kegagalan jaringan dan batas waktu terlampaui
Apa pun yang menghalangi diterimanya respons (kegagalan DNS, koneksi ditolak, atau batas waktu per permintaan terlampaui) melempar APIConnectionError. SDK tidak pernah meneruskan TypeError atau AbortError bawaan dari fetch.
APIConnectionError tidak berarti permintaan tidak pernah sampai ke server. Kegagalan DNS atau koneksi ditolak memang menghentikan permintaan sebelum mencapai API, tetapi batas waktu terlampaui menggunakan kelas yang sama, dan permintaan mungkin telah tiba serta selesai diproses setelah klien berhenti menunggu. Perlakukan kondisi ini sebagai hasil tidak diketahui: Anda dapat mencoba ulang operasi baca secara bebas, dan untuk operasi tulis, baca kembali rekaman sebelum mengulanginya karena API tidak mendeteksi penulisan berulang.
Batas waktu diterapkan secara internal menggunakan AbortSignal.timeout pada setiap percobaan, secara default sebesar 240000 ms, dan dapat dikonfigurasi melalui opsi konstruktor timeout. Percobaan yang melampaui batas waktu dicoba ulang seperti kegagalan koneksi lainnya; hanya kegagalan terakhir yang dilempar:
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);}}Referensi terkait
- Konfigurasi, opsi
timeoutdanmaxRetries - Panduan mulai cepat, contoh minimal penanganan kesalahan
- Contoh penggunaan, penanganan kesalahan dalam penggunaan nyata pada skrip lengkap