Gestione degli errori e stati HTTP

HTTP · Codici di stato · Gestione degli errori

Gestione degli errori

L'API utilizza codici di stato HTTP standard e messaggi di errore strutturati in formato JSON per garantire una gestione coerente degli errori.


Codici di stato HTTP

CodiceStatoDescrizione
200OKRichiesta riuscita (GET, POST, DELETE)
201CreataNuova risorsa creata (POST)
400Richiesta non validaCorpo della richiesta non valido, parametri mancanti o parametro di query non valido (a partire dalla versione v2.122.10 su ogni endpoint JSON, vedi sotto)
401Non autorizzatoToken assente o non valido
403ForbiddenIl token non dispone degli ambiti necessari
404Non trovatoRisorsa non trovata
409ConflittoImpossibile eliminare la risorsa (controllo di sicurezza)
429Troppe richiesteLimite di richieste superato; Retry-After indica il tempo di attesa in secondi
500Errore interno del serverErrore del server

Formato della risposta di errore

HTTP/1.1 401 Unauthorized
X-XoPort-Deny-Reason: deny_token_required
Content-Type: application/json; charset=utf-8

{
  "success": false,
  "api_version": "2.122.13",
  "error": {
    "code": "UNAUTHORIZED",
    "reason": "deny_token_required",
    "message": "Authentication required. JSON/REST routes always require an OAuth2 token and check its scopes; the XML_PORT_IP_FILTER whitelist does not authorize them (changed in API 2.119.0). Obtain a token via POST /oauth/token (client_credentials grant)."
  }
}

Gli errori relativi ai parametri di richiesta contengono inoltre i campi details[], param e message per ogni errore (esempio nella pagina API di esportazione). Valutate error.code, non il testo del messaggio.

A partire dalla versione v2.119.0, in caso di richiesta rifiutata l'API indica il motivo nel campo reason; in caso di errore 401, lo indica anche nell'intestazione X-XoPort-Deny-Reason: ad esempio deny_token_required (401, richiesta senza token) o deny_ip_not_listed (403, indirizzo non presente in XOPORT_REST_IP_LIST; solo nel corpo del messaggio).

Codici di errore comuni

CodiceHTTPDescrizione
INVALID_FILTER_VALUE400Un parametro di richiesta contiene un valore non valido o un valore di elenco (?status[]=1); details[] riporta per ciascun errore param e message. A partire dalla versione v2.122.10, su ogni endpoint JSON, compresi Import e Delete; in tal caso non viene letto, scritto o cancellato nulla
INVALID_PAGINATION400limit, offset, page, sort o order non funzionano (details[] come sopra)
INVALID_RANGE400Forma del percorso o segmento del percorso non valido: new:{datum} in un endpoint diverso da clienti e ordini (dalla v2.122.10); nell’esportazione JSON dalla v2.122.12 anche un segmento che non sia né un numero intero, né un intervallo, né una sottoruta (/product/42x, /order/42.0, /contracts/10/20). Il messaggio indica il segmento
FILTER_NOT_APPLICABLE400filtro applicato a una singola richiesta o a un intervallo di ID su cui non ha effetto; a partire dalla v2.122.13 anche ?categories_id= insieme all’ID o all’intervallo nel percorso dell’elenco dei prodotti per categoria (/categories/5/productlist?categories_id=7, /categories/5:10/productlist?categories_id=5). Rimane consentito solo lo stesso valore dell’ID del percorso singolo
INVALID_STATUS400status_id nell’endpoint di stato PUT /Import/JSON/contracts/{id}/status non corrisponde a uno stato contrattuale del negozio o non è un numero intero. A partire dalla v2.122.13, error.valid_status_ids elenca gli ID validi; fino alla v2.122.12, l’endpoint verificava lo stato dell’ordine
UNKNOWN_FILTER200 o 400Nome parametro sconosciuto durante l’esportazione: avviso su warnings[], con ?_strict=true HTTP 400
MISSING_ID400Cancellazione senza ID nel percorso; l’ID deve essere incluso nel percorso, ad esempio DELETE /…/categories/99
UNAUTHORIZED401Token di accesso assente, non valido o scaduto, oppure il client è disattivato; error.reason e l’intestazione X-XoPort-Deny-Reason indicano il motivo
IP_NOT_ALLOWED403Richiesta proveniente da un indirizzo non presente in XOPORT_REST_IP_LIST (a partire dalla v2.119.0)
INSUFFICIENT_PERMISSIONS403Il token non include l’ambito dell’endpoint (message: «Required scope: …»)
NOT_FOUND404Risorsa non trovata: richiesta singola senza risultati su /product/{id}, /products/{id} e /order_status/{id} (a partire dalla v2.122.10), oltre a file multimediali, allegati ai ticket, documenti giustificativi e DELETE con un ID sconosciuto. Le altre richieste singole rispondono con HTTP 200 e data vuoto. Anche un URL di base errato restituisce un 404 NOT_FOUND
HAS_SUBCATEGORIES409La categoria ha delle sottocategorie
HAS_PRODUCTS409La categoria contiene prodotti
HAS_NEWS409La categoria "Notizie" contiene articoli
HAS_ORDERS409Il cliente ha effettuato ordini
RATE_LIMIT_EXCEEDED429Limite di richieste del client superato; a partire dalla versione v2.122.11 con error.retry_after

L'endpoint dei token POST /oauth/token risponde nel formato OAuth2 (error, error_description), non con questi codici: vedi "Errore all'endpoint dei token" più sotto.

Una modifica dell’ambito sul client ha effetto solo con il token successivo: un token già emesso mantiene gli ambiti al momento dell’emissione fino alla scadenza, ovvero fino a un’ora. È possibile revocare immediatamente l’accesso nel backend tramite «Revoca token» nel menu delle azioni del client (a partire dalla versione 4.9.168 di Shop); nelle versioni precedenti di Shop, disattivare e riattivare il client; il segreto rimane invariato. Una modifica al limite di richieste, invece, ha effetto immediato.

Nel log di utilizzo del client non compaiono le interruzioni dell’esportazione con codice HTTP 400 prima dell’esecuzione di una richiesta (errori di filtro, di scorrimento e di percorso) né la risposta 429. Chi cerca un errore in quel registro non troverà quindi questi casi; tuttavia, i codici 400 vengono comunque conteggiati ai fini del limite di richieste.

Modificato nella v2.122.10:
  • I valori non validi e i valori di elenco dei parametri di richiesta generano un codice HTTP 400 « INVALID_FILTER_VALUE » su ogni endpoint JSON (per le operazioni di importazione e cancellazione, rispettivamente «… Nothing was written» e «… Nothing was deleted»). Fino alla v2.122.9, un filtro di questo tipo veniva solitamente ignorato e la risposta arrivava non filtrata con codice HTTP 200. Regole ed esempi: API di esportazione.
  • GET /product/{id} e /products/{id} per un articolo cancellato o mai assegnato generano un codice HTTP 404 NOT_FOUND (messaggio «Product with id=… not found») anziché un codice HTTP 200 con data vuoto. Chi interrompe l’operazione in caso di risposte diverse dai codici 2xx, ora riceve questo caso come errore.
  • new:{datum} su un endpoint diverso da quello relativo a clienti e ordini restituisce un codice HTTP 400 INVALID_RANGE.
Modificato nella v2.122.12:
  • Un segmento di percorso non valido nell’esportazione JSON genera un codice di stato HTTP 400 INVALID_RANGE. Fino alla v2.122.11, con codice di stato HTTP 200 veniva restituito l’elenco sfogliato, e forme come 1e3, 4.2 o +5 erano considerate ID. Regole ed esempi: API di esportazione, sezione «Segmento di percorso».
  • Gli spazi vuoti ai margini di un valore di query o di un ID nel percorso non vengono più considerati. Alcune richieste che in precedenza superavano il controllo dei valori ma producevano comunque un risultato diverso, ora restituiscono un errore o un risultato diverso; ad esempio, ?_strict=true%0A con un filtro sconosciuto ora restituisce un codice HTTP 400.
Modificato nella v2.122.13:
  • Stato del contratto: l’endpoint di stato PUT /Import/JSON/contracts/{id}/status verifica status_id rispetto agli stati del contratto del negozio anziché rispetto agli stati dell’ordine. Un ID che esiste solo come stato dell’ordine restituisce ora un codice HTTP 400 INVALID_STATUS, mentre uno stato del contratto che non esiste anche come stato dell’ordine viene registrato. Leggere gli ID da contracts_statuses[], da GET /Export/JSON/contracts o da error.valid_status_ids, mai da /order_statuses. L’importazione del contratto segnala un ID non valido (ad esempio un ID che corrisponde esclusivamente allo stato dell’ordine) con l’avviso CONTRACT_STATUS_UNKNOWN: il record viene salvato, ma lo stato no.
  • Elenco prodotti per categoria: ?categories_id= insieme all’ID o all’intervallo nel percorso genera un errore HTTP 400 FILTER_NOT_APPLICABLE, tranne che con lo stesso valore dell’ID del singolo percorso. Fino alla versione v2.122.12, con codice di stato HTTP 200 veniva restituita la categoria del parametro. Inviare la categoria nel percorso o come parametro.

Limite di richieste superato (429)

A partire dalla v2.122.11, Retry-After indica i secondi che devono trascorrere prima che venga accettata una nuova richiesta (da 1 a 3600), e il corpo della risposta riporta lo stesso numero come error.retry_after. A ciò si aggiungono le intestazioni X-RateLimit-Limit, X-RateLimit-Remaining e X-RateLimit-Reset, che ogni risposta invia a un client con limite di richieste (vedi client OAuth2).

HTTP/1.1 429 Too Many Requests
Retry-After: 1260
X-RateLimit-Limit: 5000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1792327500
Content-Type: application/json; charset=utf-8

{
  "success": false,
  "api_version": "2.122.13",
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit of 5000 requests per 3600 s (sliding window) exceeded.",
    "retry_after": 1260
  }
}
  • Il valore determinante per il tentativo successivo è Retry-After. Nella maggior parte dei casi, «ora + Retry-After» corrisponde esattamente a X-RateLimit-Reset; se il limite di un client è stato appena ridotto, il valore risultante è Retry-After.
  • Fino alla versione v2.122.10 (Shop fino alla 4.9.170) Retry-After era sempre 3600, non esisteva un campo retry_after e il messaggio era «Rate limit of 5000 requests/hour exceeded.». Prendete come riferimento error.code, mai il testo del messaggio.
  • Una richiesta respinta (429) non viene conteggiata. È consigliabile distribuire un numero elevato di richieste in modo uniforme nell’arco dell’ora e rallentare non appena X-RateLimit-Remaining raggiunge lo 0, invece di attendere il 429.

Errore nell’endpoint del token

POST /oauth/token risponde nel formato OAuth2 con error e error_description. A partire dalla v2.122.11, uno scope richiesto che non è leggibile (UTF-8 non valido o un elenco come scope[]=…) genera un errore HTTP 400 invalid_scope; non viene emesso alcun token. client_id o client_secret come elenco generano un errore HTTP 400 invalid_request. Per quanto riguarda il limite proprio dell’endpoint del token, Retry-After indica il tempo di attesa (da 1 a 300 secondi). Tutti gli errori relativi all’endpoint del token sono riportati nella sezione OAuth2 Clients.

Best practice

Controllate sempre il campo « success » nella risposta e implementate una logica di riprova per gli errori 429 e 5xx.