Lingara Lingara Documentation Guides API Bibliothèques Applications Créer Application web
Langue: Français

Erreurs et nouvelles tentatives

Cette page est traduite de l'anglais. En cas de différence, la page anglaise fait foi. Lire la page en anglais

Tout échec levé par une bibliothèque est l’une de quatre erreurs, et toutes les quatre partagent un type de base, de sorte qu’un seul gestionnaire peut toutes les intercepter.

  • Erreur d’API. L’API a refusé la requête. L’erreur porte le statut HTTP, un code stable sur lequel brancher votre logique, et un message dans la langue que vous avez demandée.
  • Erreur OAuth. Le point de terminaison de jetons a refusé vos identifiants ou les portées demandées.
  • Erreur de maintenance. L’API est brièvement indisponible pour cause de maintenance.
  • Erreur de transport. Aucune réponse exploitable n’est arrivée : la connexion a échoué ou expiré, ou la réponse n’a pas pu être lue.

Annuler un appel n’est pas une erreur. L’annulation se manifeste sous la forme propre à votre langage.

Ce qui est retenté

Une réponse 429 ou 503 qui indique combien de temps attendre, dans un en-tête Retry-After de 60 secondes ou moins, est retentée après exactement ce délai. Un appel fait au plus 3 tentatives. Vous pouvez désactiver les nouvelles tentatives en fixant le maximum à 1.

Tout le reste est levé immédiatement :

  • une réponse 429 ou 503 sans Retry-After ;
  • une attente de plus de 60 secondes, que la bibliothèque ne passera pas à l’intérieur de votre appel. L’erreur porte retry_after, pour que vous puissiez planifier vous-même la nouvelle tentative ;
  • une erreur de transport, car la requête a peut-être déjà atteint l’API ;
  • tout flux qui a déjà livré un événement.
Langage de l'exemple de code

TypeScript

import { ApiError, MaintenanceError, OAuthError, TransportError } from "@lingara/api";

try {
  await client.getUsage();
} catch (e) {
  if (e instanceof ApiError) {
    // A refusal from the API: e.status, e.code (stable) and e.message (localised).
    console.error(e.status, e.code, e.message, e.retryAfter ?? "");
  } else if (e instanceof OAuthError) {
    // The token endpoint refused the credentials or the scopes.
    console.error(e.status, e.error, e.description ?? "");
  } else if (e instanceof MaintenanceError) {
    console.error("under maintenance; retry after", e.retryAfter ?? "a while");
  } else if (e instanceof TransportError) {
    // No usable answer: connect, tls, reset, timeout, and so on.
    console.error("transport:", e.kind);
  } else {
    throw e;
  }
}

Rust

use lingara::Error;

let result = client.get_usage().await;
if let Some(wait) = result.as_ref().err().and_then(Error::retry_after) {
    eprintln!("the API asks you to retry after {wait:?}");
}
match result {
    Ok(usage) => println!("{} allowance rows", usage.allowance.len()),
    // A refusal from the API: status, code (stable) and message (localised).
    Err(Error::Api(e)) => eprintln!("{} {} {}", e.status, e.code, e.message),
    // The token endpoint refused the credentials or the scopes.
    Err(Error::OAuth(e)) => eprintln!("{} {} {}", e.status, e.error, e.description.unwrap_or_default()),
    Err(Error::Maintenance(_)) => eprintln!("the API is under maintenance"),
    // No usable answer: connect, tls, reset, timeout, and so on.
    Err(Error::Transport(e)) => eprintln!("transport: {}", e.kind),
    Err(other) => return Err(other.into()),
}

Go

_, err := client.GetUsage(ctx)
var apiErr *lingara.APIError
var oauthErr *lingara.OAuthError
var maintenance *lingara.MaintenanceError
var transport *lingara.TransportError
switch {
case err == nil:
case errors.As(err, &apiErr):
	// A refusal from the API: Status, Code (stable) and Message (localised).
	fmt.Println(apiErr.Status, apiErr.Code, apiErr.Message)
	if apiErr.RetryAfter != nil {
		fmt.Println("retry after", *apiErr.RetryAfter)
	}
case errors.As(err, &oauthErr):
	// The token endpoint refused the credentials or the scopes.
	fmt.Println(oauthErr.Status, oauthErr.ErrorCode, oauthErr.Description)
case errors.As(err, &maintenance):
	fmt.Println("under maintenance")
	if maintenance.RetryAfter != nil {
		fmt.Println("retry after", *maintenance.RetryAfter)
	}
case errors.As(err, &transport):
	// No usable answer: connect, tls, reset, timeout, and so on.
	fmt.Println("transport:", transport.Kind)
default:
	// ctx was cancelled or timed out: errors.Is(err, context.Canceled).
	fmt.Println(err)
}

Java

try {
  client.getUsage();
} catch (LingaraException e) {
  if (e instanceof ApiException api) {
    // A refusal from the API: status(), code() (stable) and getMessage() (localised).
    System.out.println(api.status() + " " + api.code() + " " + api.getMessage());
    api.retryAfter().ifPresent(wait -> System.out.println("retry after " + wait));
  } else if (e instanceof OAuthException oauth) {
    // The token endpoint refused the credentials or the scopes.
    System.out.println(oauth.status() + " " + oauth.error() + " " + oauth.description());
  } else if (e instanceof MaintenanceException maintenance) {
    System.out.println("under maintenance");
    maintenance.retryAfter().ifPresent(wait -> System.out.println("retry after " + wait));
  } else if (e instanceof TransportException transport) {
    // No usable answer: CONNECT, TLS, RESET, TIMEOUT, and so on.
    System.out.println("transport: " + transport.kind());
  }
}
// An interrupted call throws java.util.concurrent.CancellationException instead.

Kotlin

try {
    client.getUsage()
} catch (e: LingaraException) {
    when (e) {
        // A refusal from the API: status, code (stable) and message (localised).
        is ApiException -> println("${e.status} ${e.code} ${e.message}; retry after ${e.retryAfter}")
        // The token endpoint refused the credentials or the scopes.
        is OAuthException -> println("${e.status} ${e.error} ${e.description}")
        is MaintenanceException -> println("under maintenance; retry after ${e.retryAfter}")
        // No usable answer: CONNECT, TLS, RESET, TIMEOUT, and so on.
        is TransportException -> println("transport: ${e.kind}")
    }
}
// A cancelled call throws the caller's own CancellationException instead.

Ruby

begin
  client.get_usage
rescue Lingara::ApiError => e
  # A refusal from the API: status, code (stable) and message (localised).
  puts "#{e.status} #{e.code}: #{e.message}"
  puts "retry after #{e.retry_after}s" if e.retry_after
rescue Lingara::OAuthError => e
  # The token endpoint refused the credentials or the scopes.
  puts "#{e.status} #{e.error}: #{e.description}"
rescue Lingara::MaintenanceError => e
  puts "under maintenance"
  puts "retry after #{e.retry_after}s" if e.retry_after
rescue Lingara::TransportError => e
  # No usable answer: :connect, :tls, :reset, :timeout, and so on.
  puts "transport: #{e.kind}"
end

PHP

use Lingara\Exception\ApiException;
use Lingara\Exception\LingaraException;
use Lingara\Exception\MaintenanceException;
use Lingara\Exception\OAuthException;
use Lingara\Exception\TransportException;

try {
    $client->getUsage();
} catch (LingaraException $e) {
    if ($e instanceof ApiException) {
        // A refusal from the API: status, errorCode (stable) and message (localised).
        echo $e->status(), ' ', $e->errorCode(), ': ', $e->getMessage(), "\n";
        echo 'retry after: ', $e->retryAfter() ?? 'not given', "\n";
    } elseif ($e instanceof OAuthException) {
        // The token endpoint refused the credentials or the scopes.
        echo $e->status(), ' ', $e->error(), ': ', $e->description(), "\n";
    } elseif ($e instanceof MaintenanceException) {
        echo 'under maintenance; retry after: ', $e->retryAfter() ?? 'not given', "\n";
    } elseif ($e instanceof TransportException) {
        // No usable answer: connect, tls, reset, timeout, and so on.
        echo 'transport: ', $e->kind()->value, "\n";
    }
}