Preskočiť na obsah

Spracovanie chýb ​

ApiPresenter chybové odpovede nikdy nevytvára sám. Zavolá službu ErrorHandlerInterface, zvyčajne DefaultErrorHandler.

Rozhranie a predvolené odpovede ​

MetódaVolá sa, keďDefaultErrorHandler odpovie
handle(Throwable, array $params)handle() vyhodil výnimku500 Internal server error, loguje do Tracy
handleInputParams(array $errors)parametre sú neplatné400 wrong input
handleSchema(array $errors, array $params)kontrola výstupu zlyhala500 Internal server error, loguje do Tracy
handleAuthorization(ApiAuthorizationInterface, array $params)authorized() je false401 s getErrorMessage()
handleAuthorizationException(Throwable, array $params)authorized() vyhodil výnimku500 Internal server error, loguje do Tracy
handleNotFound(EndpointInterface)URL nezodpovedá žiadny endpoint404 Unknown api endpoint
handleRateLimit(RateLimitResponse)limit je vyčerpaný a nemá vlastnú odpoveď429 Too many requests., ak je čas známy, aj Retry after N seconds.

Všetky vracajú ResponseInterface; DefaultErrorHandler vracia JsonApiResponse so status: error a message.

Od verzie 4.0.0

handleNotFound() a handleRateLimit() sú nové, takže 404 a 429 sa dajú zmeniť na jednom mieste. Metódy vracajú ResponseInterface namiesto JsonApiResponse. handleAuthorizationException() už nepošle text výnimky, ak nie sú zapnuté detaily. Pozrite si návod na upgrade.

Pre nové projekty odporúčame chyby application/problem+json podľa RFC 9457 cez ProblemDetailsErrorHandler, pozrite si Problem Details. DefaultErrorHandler ostáva predvolený, aby klienti, ktorí čítajú message, fungovali ďalej.

Detaily chýb ​

DefaultErrorHandler(ConfiguratorInterface) pridá detail, keď je showErrorDetail() konfigurátora true: text výnimky pre 500 (aj z authorized()), chyby jednotlivých polí pre 400, chyby schémy pre pokazený výstup.

json
{"status":"error","message":"Internal server error","detail":"Database connection refused"}

Ktorý konfigurátor použiť, opisujú Výstupy. V produkcii majú byť detaily vypnuté.

Vlastný error handler ​

DefaultErrorHandler je final, takže ho obaľte. Príklad logovania zmení jednu výnimku na 503 a zvyšok nechá predvolenému:

php
<?php

declare(strict_types=1);

namespace App;

use Throwable;
use Tomaj\NetteApi\Authorization\ApiAuthorizationInterface;
use Tomaj\NetteApi\EndpointInterface;
use Tomaj\NetteApi\Error\ErrorHandlerInterface;
use Tomaj\NetteApi\RateLimit\RateLimitResponse;
use Tomaj\NetteApi\Response\JsonApiResponse;
use Tomaj\NetteApi\Response\ResponseInterface;

/**
 * Answers MaintenanceException with 503 and leaves everything else to DefaultErrorHandler.
 */
final class AppErrorHandler implements ErrorHandlerInterface
{
    public function __construct(private ErrorHandlerInterface $inner)
    {
    }

    public function handle(Throwable $exception, array $params): ResponseInterface
    {
        if ($exception instanceof MaintenanceException) {
            return new JsonApiResponse(503, ['status' => 'error', 'message' => 'Down for maintenance, try again later']);
        }
        return $this->inner->handle($exception, $params);
    }

    public function handleInputParams(array $errors): ResponseInterface
    {
        return $this->inner->handleInputParams($errors);
    }

    public function handleSchema(array $errors, array $params): ResponseInterface
    {
        return $this->inner->handleSchema($errors, $params);
    }

    public function handleAuthorization(ApiAuthorizationInterface $auth, array $params): ResponseInterface
    {
        return $this->inner->handleAuthorization($auth, $params);
    }

    public function handleAuthorizationException(Throwable $exception, array $params): ResponseInterface
    {
        return $this->inner->handleAuthorizationException($exception, $params);
    }

    public function handleNotFound(EndpointInterface $endpoint): ResponseInterface
    {
        return $this->inner->handleNotFound($endpoint);
    }

    public function handleRateLimit(RateLimitResponse $rateLimit): ResponseInterface
    {
        return $this->inner->handleRateLimit($rateLimit);
    }
}
yaml
services:
	defaultErrorHandler:
		factory: Tomaj\NetteApi\Error\DefaultErrorHandler
		autowired: false
	- App\AppErrorHandler(@defaultErrorHandler)

autowired: false zabezpečí, že na autowiring ostane jediný ErrorHandlerInterface.

Časté otázky ​

Prečo produkcia vráti 400 bez toho, aby povedala, ktoré pole je zlé? ​

DefaultErrorHandler skryje detail pre všetky kódy, keď je showErrorDetail() false, vrátane 400. DefaultErrorHandler je final, preto implementujte ErrorHandlerInterface, všetky metódy delegujte na obalený DefaultErrorHandler ako v časti Vlastný error handler a v handleInputParams() vráťte new JsonApiResponse(400, ['status' => 'error', 'message' => 'wrong input', 'detail' => $errors]).

Ako pošlem 404 pre chýbajúci záznam? ​

Vráťte ho z handlera: new JsonApiResponse(404, [...]). Error handlery sú na neočakávané zlyhania. Pozrite si Handlery.

Kde uvidím výnimku? ​

V adresári logov Tracy, exception.log a HTML súbor pre každú výnimku. Príklad logovania to kontroluje.

Môžu chyby autorizácie mať vlastný stavový kód? ​

Rozhoduje váš error handler; handleAuthorization() dostane objekt autorizácie a môže z neho čítať čokoľvek. Pozrite si Autorizáciu.

Je pokazený výstup chybou v produkcii? ​

Len ak tam konfigurátor výstupy validuje. S EnvConfigurator a APP_ENV=production sa odpoveď pošle bez kontroly.

Vydané pod licenciou MIT.