API di FlavosoFondamentiErrori

Errori

Ogni errore ha la stessa forma. Qui trovi tutti i codici con lo stato HTTP e cosa deve fare il tuo programma.

La forma

Un errore è sempre un oggetto error con code, message e request_id, e con invalid_request spesso anche param:

{
  "error": {
    "code": "invalid_request",
    "message": "price must be an integer amount in cents.",
    "request_id": "req_4f0c2a9d1e7b3c5a8f6d2e10",
    "param": "products[3].price"
  }
}
  • code è il contratto: il tuo programma può farci affidamento, non viene mai riformulato.
  • message è un'indicazione in inglese per gli sviluppatori e può cambiare. Non mostrarla al ristoratore.
  • request_id è anche nell'intestazione X-Request-Id; con questo trovi la richiesta nel registro.
  • param indica il campo errato, anche in profondità nel corpo: products[3].price.

Tutti i codici

CodiceHTTPSignificatoCosa fa il tuo programma
invalid_request400Un parametro o il corpo non è corretto: manca un campo obbligatorio, un tipo è sbagliato, il JSON non è valido, oppure la richiesta contiene un campo o un parametro di query che l'operazione non conosce. param indica il campo, se si tratta di un campo.Non ripetere la richiesta invariata. Correggila in base a param e message.
unauthorized401Nessun token, un token scaduto o revocato, il collegamento non esiste più oppure l'app è bloccata.Ottieni un nuovo token di accesso con il token di aggiornamento e riprova una volta. Se fallisce con invalid_grant, il collegamento non esiste più; con unauthorized_client l'app è bloccata: conserva i token e riprova più tardi.
account_inactive403L'abbonamento del locale non è attivo. GET /me e DELETE /connection funzionano comunque.Non ripetere subito. Riprova più tardi o informa il locale.
insufficient_scope403Al collegamento manca il permesso per questa operazione. WWW-Authenticate lo indica.Chiedi al titolare di collegare di nuovo la tua app con questo permesso. Fino ad allora disattiva la funzione.
plan_required403Il piano del locale non include la funzione, per esempio le prenotazioni nel piano Starter.Disattiva la funzione per questo locale e mostra all'utente il motivo.
not_found404L'oggetto non esiste, o non in questo locale. Vale anche per un percorso sconosciuto.Controlla identificativo e percorso. Rimuovi dal tuo archivio un oggetto eliminato.
method_not_allowed405Questo metodo non esiste su questo percorso.Confronta metodo e percorso con il riferimento.
conflict409Gli stessi dati sono stati modificati altrove nello stesso momento, per esempio dal locale nella dashboard, tre volte di fila. La richiesta in sé è corretta.Aspetta Retry-After secondi e invia di nuovo la stessa richiesta invariata, con lo stesso Idempotency-Key.
external_id_taken409Questo external_id è già associato, per la tua app in questo locale, a un altro oggetto dello stesso tipo.Con ?external_id= controlla quale oggetto lo usa e correggi l'associazione nel tuo sistema.
idempotency_in_progress409Una prima richiesta con lo stesso Idempotency-Key è ancora in corso.Aspetta un momento e riprova con la stessa chiave.
invalid_transition409Questo cambio di stato non è possibile, per esempio all'indietro o da uno stato concluso. Per le prenotazioni message indica gli stati possibili in quel momento.Rileggi l'oggetto: di solito è già stato modificato altrove. Poi decidi.
slot_unavailable409L'orario non è un orario prenotabile del giorno o è già passato, oppure a quell'orario non c'è posto per questo numero di persone o per questi tavoli.Recupera gli orari liberi con GET /reservations/availability e proponine uno.
stage_not_used409Il locale non usa questo stato, per esempio preparing. GET /store indica quelli usati sotto order_statuses.Salta il passo e passa allo stato successivo.
payload_too_large413Il corpo è più grande di quanto l'operazione accetta, contato in byte: 64 KB, 2 MB per PUT /menu.Dividi la richiesta, per esempio il menu in più sincronizzazioni con merge.
idempotency_key_reused422Lo stesso Idempotency-Key è arrivato con una richiesta diversa (metodo, percorso o corpo).Usa una nuova chiave per ogni nuova operazione. Cerca l'errore nel programma.
limit_exceeded422È stato superato un limite, per esempio troppi piatti in una sincronizzazione.Dividi o riduci la richiesta. I limiti sono indicati nella guida corrispondente.
rate_limited429Più di 120 richieste al minuto per questo collegamento.Aspetta Retry-After secondi, poi continua. Distribuisci le richieste nel tempo.
server_error500Qualcosa è andato storto da parte di Flavoso.Riprova con intervalli crescenti, per i POST con lo stesso Idempotency-Key. Se il problema persiste, invia il request_id al supporto.

Gestire gli errori

Un errore ti dice se riprovare serve. 401 significa: rinnova il token. 403 significa: avvisa il titolare, non riprovare. 409 di solito significa: l'oggetto è cambiato altrove, quindi rileggilo. Ogni altro 4xx significa: la richiesta è sbagliata, quindi non ripeterla invariata.

export class FlavosoError extends Error {
  constructor(status, error) {
    super(`${status} ${error.code}: ${error.message}`);
    Object.assign(this, { status, code: error.code, param: error.param, requestId: error.request_id });
  }
}

export async function flavoso(conn, method, path, { body, idempotencyKey } = {}) {
  const res = await fetch(`https://api.flavoso.com/v1${path}`, {
    method,
    headers: {
      Authorization: `Bearer ${await accessTokenFor(conn)}`,
      ...(body ? { "Content-Type": "application/json" } : {}),
      ...(idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {}),
    },
    body: body ? JSON.stringify(body) : undefined,
  });
  const data = await res.json();
  if (res.ok) return data;
  const err = new FlavosoError(res.status, data.error);
  switch (err.code) {
    case "unauthorized": // expired or revoked: refresh once, then give up
      conn.expiresAt = 0;
      break;
    case "insufficient_scope": // ask the owner to connect again with this scope
    case "plan_required": // the restaurant's plan does not include this
    case "account_inactive": // the restaurant's subscription is not active
      await flagConnection(conn, err.code);
      break;
  }
  throw err; // log err.requestId: support can find the request with it
}

401 e un collegamento perso

Con 401 ottieni un nuovo token di accesso con il token di aggiornamento e riprovi una volta. Se anche questo fallisce con invalid_grant, il collegamento non esiste più: l'ha chiuso il titolare o la tua app, il token di aggiornamento è scaduto o è stato revocato, oppure il locale non è più attivo. Mostralo nel tuo software e offri «Ricollega»; qui riprovare non serve.

Se invece l'endpoint del token risponde unauthorized_client, la tua app è bloccata, ma i suoi collegamenti restano. Conserva i token, mostra «bloccata temporaneamente» e riprova più tardi.

Quando riprovare

CasoRiprovare?
Errore di rete, timeoutSì, con lo stesso Idempotency-Key.
429 rate_limitedSì, dopo Retry-After secondi.
500 server_error, 502, 503, 504Sì, con intervalli crescenti.
409 idempotency_in_progress, 409 conflictSì, dopo una breve pausa (Retry-After), invariata.
401 unauthorizedUna volta, dopo aver rinnovato il token.
400, 403, 404, 413, 422, altri 409No, non senza modifiche.
const RETRYABLE = new Set([429, 500, 502, 503, 504]);

// send() makes the SAME request every time, with the same Idempotency-Key.
export async function withRetries(send, attempts = 5) {
  for (let attempt = 1; ; attempt++) {
    let res = null;
    try {
      res = await send();
    } catch (err) {
      if (attempt >= attempts) throw err; // network error: outcome unknown, so retry
    }
    if (res && (!RETRYABLE.has(res.status) || attempt >= attempts)) return res;
    const retryAfter = Number(res?.headers.get("retry-after"));
    const backoff = Math.min(30, 2 ** attempt) * (0.5 + Math.random() / 2);
    await new Promise((r) => setTimeout(r, (retryAfter > 0 ? retryAfter : backoff) * 1000));
  }
}

Con il supporto

Scrivi a support@flavoso.com indicando il request_id (o X-Request-Id), più l'ora e l'operazione. Così troviamo la richiesta. Lo stesso identificativo è nel tuo registro delle richieste.

Qualcosa non è chiaro? Scrivi a support@flavoso.com indicando l'identificativo di X-Request-Id. Così troviamo la tua richiesta nel registro.