錯誤處理

Listings API Python SDK 的例外階層、錯誤屬性、HTTP 200 回應酬載中的錯誤、用戶端驗證及重試指引。

所有例外都可從頂層 listingsapi 模組匯入。

例外階層

Code
ListingsAPIError├── APIError                    API-reported failure: non-2xx, or an error payload in HTTP 200│   ├── AuthenticationError     401, or payload codes SY90005 / SY90001│   ├── PermissionDeniedError   403, or payload code SY90003│   ├── NotFoundError           404│   ├── ValidationError         400 / 422, mutation failures, client-side validation│   ├── RateLimitError          429, or payload code RATE_LIMITED (carries .retry_after)│   └── InternalServerError     5xx (safe to retry)└── APIConnectionError          network failure: DNS, connection refused, timeout

捕捉 ListingsAPIError 可處理 SDK 可能引發的所有例外,捕捉 APIError 可處理 API 回報的所有錯誤,也可捕捉特定子類別來針對性地處理。

例外屬性

APIError 及其子類別具有下列屬性:

屬性型別說明
status_codeint | NoneHTTP 狀態碼(酬載層級的錯誤可能為 200)
codestr | None第一個平台錯誤碼,e.g。SY10005
errorslist[dict]正規化後的錯誤項目,每個項目皆為 {"code", "message", "context"}
response_bodystr | NoneAPI 傳回的原始回應文字
retry_afterfloat | None僅限 RateLimitError;從 Retry-After 標頭解析取得

APIConnectionError 直接繼承自 ListingsAPIError,不具有上述任何屬性;例外訊息會說明網路失敗的情況。

捕捉例外

Python
import listingsapi client = listingsapi.ListingsAPI() try:  location = client.locations.retrieve(16808)except listingsapi.AuthenticationError as e:  print("Invalid API key:", e.code)except listingsapi.PermissionDeniedError as e:  print("Not allowed:", e.status_code)except listingsapi.NotFoundError as e:  print("No such location:", e.status_code)except listingsapi.ValidationError as e:  for err in e.errors:      print(err["code"], err["message"], err["context"])except listingsapi.RateLimitError as e:  print("Rate limited, retry in", e.retry_after, "seconds")except listingsapi.InternalServerError as e:  print("Server error (safe to retry):", e.status_code)except listingsapi.APIConnectionError as e:  print("Network failure:", e)except listingsapi.APIError as e:  print("Unexpected API error:", e.status_code, e.code, e.response_body)

HTTP 200 回應中的錯誤

平台有時會在 200 回應主體中回報失敗。SDK 會檢查每個回應並引發例外,因此您不必自行檢查 success 旗標或掃描 errors 陣列:

  • 頂層 errors[] 主體會依錯誤碼對應至例外:SY90005 和 SY90001 會引發 AuthenticationError,SY90003 會引發 PermissionDeniedError,RATE_LIMITED 會引發 RateLimitError,其他任何錯誤碼則會引發 APIError。
  • 寫入回應(建立、更新、封存、發布貼文)若傳回 success: false 或 errors[] 清單,就會引發 ValidationError。

在這 2 種情況中,status_code 都是實際的 HTTP 狀態碼(通常為 200),code 是第一個平台錯誤碼,而 errors 包含所有正規化後的項目:

Python
import listingsapi client = listingsapi.ListingsAPI() try:  result = client.locations.update({"id": 16808, "phone": "not-a-phone"})except listingsapi.ValidationError as e:  print(e.status_code)   # 200: the API accepted the request but rejected the mutation  print(e.code)          # first platform code, e.g. "SY10005"  for err in e.errors:      print(err["code"], err["message"], err["context"])

用戶端驗證

locations.add() 和貼文輔助函式(posts.create_announcement()、posts.create_event()、posts.create_offer()、posts.bulk_publish())會在本機驗證酬載,並在進行任何網路呼叫之前引發 ValidationError,因此無效的酬載會立即失敗並提供明確訊息,無須往返傳送請求與回應。

對於 locations.add():

  • name 必須為 2 至 150 個字元
  • description 必須至少為 200 個字元
  • sub_category_id 為必填項目
  • country_iso 為必填項目
  • 除非 hide_address=True(服務區域商家),否則 city 為必填項目

對於貼文輔助函式:

  • name 為必填項目,且 location_ids 不得為空
  • sites 必須是由 GOOGLE、FACEBOOK 組成的集合的非空子集
  • message 為必填項目;若使用按網站分別設定的 dict,每個目標網站都必須有文字
  • cta_type 和 cta_url 必須一併提供,且 cta_type 必須是 BOOK、ORDER、SHOP、LEARN_MORE、SIGN_UP、GET_OFFER 其中之一
  • 活動和優惠必須提供 title

對於這些在本機引發的錯誤,status_code、code 和 response_body 皆為 None,而 errors 為空;str(e) 會列出所有發現的問題:

Python
import listingsapi client = listingsapi.ListingsAPI() try:  client.locations.add(      name="Acme Dental",      description="Too short.",      sub_category_id=1432,      country_iso="US",      city="New York",  )except listingsapi.ValidationError as e:  print(e)  # Invalid location: description must be at least 200 characters (got 10)  print(e.status_code)  # None: raised before any network call

自動重試

對於 GET、HEAD 和 OPTIONS,SDK 遇到 429、500、502、503 和 504 時會自動重試(預設重試 2 次,指數退避係數為 0.5 秒,並遵循 Retry-After)。寫入操作不會重試:POST 或 DELETE 只會傳送一次,並在首次失敗時引發例外。可透過建構函式引數 max_retries 設定;請參閱設定。

v4 API 不支援 Idempotency-Key,也不會偵測重複寫入,因此逾時或傳回 5xx 的寫入操作可能已經提交。未經確認就重試,會建立第二個地點、貼文或評論回覆。重複寫入前,請先使用您掌控的索引鍵讀回該筆記錄。

遇到 RateLimitError 時採用退避

若內建重試後仍出現 429,RateLimitError.retry_after 會包含伺服器的 Retry-After 值,單位為秒(若沒有該標頭,則為 None)。以下是批次作業的簡單處理方式:

Python
import randomimport time import listingsapi client = listingsapi.ListingsAPI(max_retries=0)  # manual retry control def with_backoff(call, max_attempts=5):  for attempt in range(max_attempts):      try:          return call()      except listingsapi.RateLimitError as e:          if attempt == max_attempts - 1:              raise          if e.retry_after is not None:              delay = e.retry_after          else:              delay = min(2 ** attempt, 30) + random.random()          time.sleep(delay) page = with_backoff(lambda: client.locations.list(first=50))for location in page:  print(location.name)

匯入例外

Python
# All exceptions from the top-level moduleimport listingsapi listingsapi.ListingsAPIErrorlistingsapi.APIErrorlistingsapi.AuthenticationErrorlistingsapi.PermissionDeniedErrorlistingsapi.NotFoundErrorlistingsapi.ValidationErrorlistingsapi.RateLimitErrorlistingsapi.InternalServerErrorlistingsapi.APIConnectionError # Or import individuallyfrom listingsapi import RateLimitError, ValidationError

另請參閱

  • 設定:max_retries 和 timeout
  • 快速入門:您的第一個具備錯誤處理功能的指令碼