Gestione degli errori

Gerarchia delle eccezioni, attributi d'errore, errori nei payload HTTP 200, validazione client e guida ai nuovi tentativi: Python SDK di Listings API.

Tutte le eccezioni possono essere importate dal modulo di primo livello listingsapi.

Gerarchia delle eccezioni

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

Intercetta ListingsAPIError per gestire tutte le eccezioni che l'SDK può sollevare, APIError per tutti gli errori segnalati dall'API oppure una sottoclasse specifica per una gestione mirata.

Attributi delle eccezioni

APIError e le sue sottoclassi hanno i seguenti attributi:

AttributoTipoDescrizione
status_codeint | NoneCodice di stato HTTP (può essere 200 per gli errori a livello di payload)
codestr | NonePrimo codice di errore della piattaforma, e.g. SY10005
errorslist[dict]Voci di errore normalizzate, ciascuna {"code", "message", "context"}
response_bodystr | NoneTesto non elaborato della risposta dell'API
retry_afterfloat | NoneSolo per RateLimitError; ricavato dall'header Retry-After

APIConnectionError eredita direttamente da ListingsAPIError e non ha nessuno di questi attributi; il messaggio dell'eccezione descrive l'errore di rete.

Intercettare le eccezioni

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)

Errori nelle risposte HTTP 200

La piattaforma a volte segnala errori nel corpo di una risposta 200. L'SDK esamina ogni risposta e solleva le eccezioni, quindi non devi mai controllare i flag success o esaminare gli array errors manualmente:

  • I corpi con errors[] al primo livello vengono associati alle eccezioni in base al codice: SY90005 e SY90001 sollevano AuthenticationError, SY90003 solleva PermissionDeniedError, RATE_LIMITED solleva RateLimitError e qualsiasi altro codice solleva APIError.
  • Le risposte alle operazioni di scrittura (creazione, aggiornamento, archiviazione, pubblicazione di post) che contengono success: false o un elenco errors[] sollevano ValidationError.

In entrambi i casi, status_code è lo stato HTTP effettivo (spesso 200), code è il primo codice della piattaforma e errors contiene tutte le voci normalizzate:

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"])

Validazione lato client

locations.add() e le funzioni ausiliarie per i post (posts.create_announcement(), posts.create_event(), posts.create_offer(), posts.bulk_publish()) validano il proprio payload localmente e sollevano ValidationError prima di qualsiasi chiamata di rete, quindi un payload non valido genera subito un errore con un messaggio chiaro, senza richiedere uno scambio di dati con il server.

Per locations.add():

  • name deve contenere da 2 a 150 caratteri
  • description deve contenere almeno 200 caratteri
  • sub_category_id è obbligatorio
  • country_iso è obbligatorio
  • city è obbligatorio, salvo quando hide_address=True (attività con area di servizio)

Per le funzioni ausiliarie per i post:

  • name è obbligatorio e location_ids non deve essere vuoto
  • sites deve essere un sottoinsieme non vuoto di GOOGLE, FACEBOOK
  • message è obbligatorio; quando è un dict con valori per sito, ogni sito di destinazione deve avere un testo
  • cta_type e cta_url devono essere forniti insieme e cta_type deve essere uno dei seguenti valori: BOOK, ORDER, SHOP, LEARN_MORE, SIGN_UP, GET_OFFER
  • title è obbligatorio per eventi e offerte

Per questi errori sollevati localmente, status_code, code e response_body sono None e errors è vuoto; str(e) elenca tutti i problemi rilevati:

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

Tentativi automatici

L'SDK riprova automaticamente in caso di 429, 500, 502, 503 e 504 per GET, HEAD e OPTIONS (per impostazione predefinita, 2 tentativi aggiuntivi, fattore di attesa esponenziale di 0,5 secondi, rispetto di Retry-After). Le operazioni di scrittura non vengono ritentate: una richiesta POST o DELETE viene inviata una sola volta e solleva un'eccezione al primo errore. Configura questo comportamento tramite l'argomento max_retries del costruttore; vedi Configurazione.

L'API v4 non supporta Idempotency-Key e non rileva le operazioni di scrittura ripetute, quindi un'operazione di scrittura che supera il tempo limite o restituisce 5xx potrebbe essere già stata completata. Ripeterla senza verifiche creerebbe una seconda sede, un secondo post o una seconda risposta a una recensione. Rileggi il record usando una chiave sotto il tuo controllo prima di ripetere un'operazione di scrittura.

Attendere prima di riprovare dopo un RateLimitError

Quando un'eccezione 429 persiste dopo i tentativi automatici integrati, RateLimitError.retry_after contiene il valore Retry-After del server in secondi (oppure None se l'header era assente). Un semplice esempio per le elaborazioni in batch:

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)

Importare le eccezioni

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

Vedi anche