Lingara Lingara Dokumentasi Panduan API Pustaka Aplikasi Bina Apl web
Bahasa: Bahasa Melayu

Ralat dan cubaan semula

Halaman ini diterjemahkan daripada bahasa Inggeris. Jika kedua-duanya berbeza, halaman bahasa Inggeris adalah yang betul. Baca halaman bahasa Inggeris

Setiap kegagalan yang dilontarkan oleh pustaka ialah salah satu daripada empat ralat, dan keempat-empatnya berkongsi jenis asas, jadi satu pengendali boleh menangkap kesemuanya.

  • Ralat API. API menolak permintaan. Ia membawa status HTTP, code yang stabil untuk dijadikan cabang, dan mesej dalam bahasa yang anda minta.
  • Ralat OAuth. Endpoint token menolak kelayakan anda atau skop yang anda minta.
  • Ralat penyelenggaraan. API tidak tersedia buat seketika kerana penyelenggaraan.
  • Ralat pengangkutan. Tiada jawapan yang boleh digunakan tiba: sambungan gagal atau tamat masa, atau respons tidak dapat dibaca.

Membatalkan panggilan bukan ralat. Ia muncul sebagai mekanisme pembatalan bahasa anda sendiri.

Apa yang dicuba semula

429 atau 503 yang menyatakan berapa lama perlu menunggu, dalam pengepala Retry-After sebanyak 60 saat atau kurang, dicuba semula selepas menunggu tepat selama itu. Satu panggilan membuat paling banyak 3 cubaan. Anda boleh mematikan cubaan semula dengan menetapkan maksimum kepada 1.

Semua yang lain dilontarkan serta-merta:

  • 429 atau 503 tanpa Retry-After;
  • tempoh menunggu lebih daripada 60 saat, yang tidak akan dihabiskan oleh pustaka di dalam panggilan anda. Ralat itu membawa retry_after, jadi anda boleh menjadualkan cubaan semula sendiri;
  • ralat pengangkutan, kerana permintaan itu mungkin sudah sampai ke API;
  • mana-mana strim yang telah menghantar sesuatu peristiwa.
Bahasa contoh kod

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";
    }
}