Gestion des erreurs

Hiérarchie des exceptions, attributs d’erreur, erreurs du contenu HTTP 200, validation côté client et conseils de réessai du Python SDK Listings API.

Toutes les exceptions peuvent être importées depuis le module de premier niveau listingsapi.

Hiérarchie des exceptions

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

Interceptez ListingsAPIError pour gérer toutes les exceptions que le SDK peut lever, APIError pour gérer toutes celles signalées par l'API, ou une sous-classe spécifique pour un traitement ciblé.

Attributs des exceptions

APIError et ses sous-classes possèdent les attributs suivants :

AttributTypeDescription
status_codeint | NoneCode de statut HTTP (peut être 200 pour les erreurs dans les données de la réponse)
codestr | NonePremier code d'erreur de la plateforme, e.g. SY10005
errorslist[dict]Entrées d'erreur normalisées, chacune au format {"code", "message", "context"}
response_bodystr | NoneTexte brut de la réponse de l'API
retry_afterfloat | NoneRateLimitError uniquement ; extrait de l'en-tête Retry-After

APIConnectionError hérite directement de ListingsAPIError et ne possède aucun de ces attributs ; le message de l'exception décrit la défaillance réseau.

Interception des exceptions

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)

Erreurs dans les réponses HTTP 200

La plateforme signale parfois des échecs dans le corps d'une réponse 200. Le SDK inspecte chaque réponse et lève les exceptions correspondantes : vous n'avez donc jamais à vérifier vous-même les indicateurs success ni à parcourir les tableaux errors :

  • Les corps errors[] de premier niveau sont associés à une exception selon leur code : SY90005 et SY90001 lèvent AuthenticationError, SY90003 lève PermissionDeniedError, RATE_LIMITED lève RateLimitError et tout autre code lève APIError.
  • Les réponses aux opérations d'écriture (création, mise à jour, archivage, publication de posts) qui contiennent success: false ou une liste errors[] lèvent ValidationError.

Dans les deux cas, status_code correspond au statut HTTP réel (souvent 200), code est le premier code de la plateforme et errors contient toutes les entrées normalisées :

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

Validation côté client

locations.add() et les fonctions utilitaires pour les posts (posts.create_announcement(), posts.create_event(), posts.create_offer(), posts.bulk_publish()) valident leurs données localement et lèvent ValidationError avant tout appel réseau, de sorte que des données incorrectes provoquent un échec immédiat avec un message clair, sans aller-retour réseau.

Pour locations.add() :

  • name doit comporter entre 2 et 150 caractères
  • description doit comporter au moins 200 caractères
  • sub_category_id est obligatoire
  • country_iso est obligatoire
  • city est obligatoire, sauf si hide_address=True (entreprises desservant une zone géographique)

Pour les fonctions utilitaires pour les posts :

  • name est obligatoire et location_ids ne doit pas être vide
  • sites doit être un sous-ensemble non vide de GOOGLE, FACEBOOK
  • message est obligatoire ; lorsqu'il s'agit d'un dict par site, chaque site cible doit avoir du texte
  • cta_type et cta_url doivent être fournis ensemble, et cta_type doit avoir l'une des valeurs suivantes : BOOK, ORDER, SHOP, LEARN_MORE, SIGN_UP, GET_OFFER
  • title est obligatoire pour les événements et les offres

Pour ces erreurs levées localement, status_code, code et response_body valent None et errors est vide ; str(e) répertorie tous les problèmes détectés :

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

Nouvelles tentatives automatiques

Le SDK effectue automatiquement de nouvelles tentatives en cas de 429, 500, 502, 503 et 504 pour GET, HEAD et OPTIONS (2 nouvelles tentatives par défaut, facteur de temporisation exponentielle de 0,5 seconde, respect de Retry-After). Les opérations d'écriture ne sont pas retentées : une requête POST ou DELETE est envoyée une seule fois et lève une exception dès le premier échec. Configurez ce comportement à l'aide de l'argument max_retries du constructeur ; voir Configuration.

L'API v4 ne prend pas en charge Idempotency-Key et ne détecte pas les écritures répétées ; une écriture dont le délai d'attente expire ou qui renvoie 5xx peut donc avoir déjà été enregistrée. La retenter sans vérification créerait un deuxième établissement, post ou réponse à un avis. Relisez l'enregistrement à l'aide d'une clé que vous contrôlez avant de répéter une écriture.

Temporisation en cas de RateLimitError

Lorsqu'une exception 429 persiste après les nouvelles tentatives intégrées, RateLimitError.retry_after contient la valeur Retry-After du serveur en secondes (ou None si l'en-tête était absent). Voici un exemple simple pour les traitements par lots :

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)

Importation des exceptions

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

Voir aussi