Errors Handling

API Platform comes with a powerful error system. It handles expected (such as faulty JSON documents sent by the client or validation errors) as well as unexpected errors (PHP exceptions and errors). API Platform automatically sends the appropriate HTTP status code to the client: 400 for expected errors, 500 for unexpected ones. It also provides a description of the error in the Hydra error format or in the format described in the RFC 7807, depending of the format selected during the content negotiation.

API Platform には強力なエラー システムが付属しています。 API プラットフォームは、予期されるエラー (クライアントから送信された欠陥のある JSON ドキュメントや検証エラーなど) と予期しないエラー (PHP の例外とエラー) を処理します。API プラットフォームは、適切な HTTP ステータス コードをクライアントに自動的に送信します。また、コンテンツ ネゴシエーション中に選択された形式に応じて、RFC 7807 で説明されている形式で Hydra エラー フォーマッタのエラーの説明も提供します。

Converting PHP Exceptions to HTTP Errors

The framework also allows you to configure the HTTP status code sent to the clients when custom exceptions are thrown on an API Platform resource operation.

このフレームワークでは、API プラットフォーム リソース操作でカスタム例外がスローされたときにクライアントに送信される HTTP ステータス コードを構成することもできます。

In the following example, we throw a domain exception from the business layer of the application and configure API Platform to convert it to a 404 Not Found error:

次の例では、アプリケーションのビジネス レイヤーからドメイン例外をスローし、それを 404 Not Found エラーに変換するように API プラットフォームを構成します。

<?php
// api/src/Exception/ProductNotFoundException.php
namespace App\Exception;

final class ProductNotFoundException extends \Exception
{
    // ...
}
<?php
// api/src/EventSubscriber/ProductManager.php
namespace App\EventSubscriber;

use ApiPlatform\EventListener\EventPriorities;
use App\Entity\Product;
use App\Exception\ProductNotFoundException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\KernelEvents;

final class ProductManager implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [
            KernelEvents::VIEW => ['checkProductAvailability', EventPriorities::PRE_VALIDATE],
        ];
    }

    public function checkProductAvailability(ViewEvent $event): void
    {
        $product = $event->getControllerResult();
        if (!$product instanceof Product || !$event->getRequest()->isMethodSafe(false)) {
            return;
        }

        if (!$product->isPubliclyAvailable()) {
            // Using internal codes for a better understanding of what's going on
            throw new ProductNotFoundException(sprintf('The product "%s" does not exist.', $product->getId()));
        }
    }
}

If you use the standard distribution of API Platform, this event listener will be automatically registered. If you use a custom installation, learn how to register listeners.

API Platform の標準ディストリビューションを使用する場合、このイベント リスナーは自動的に登録されます。カスタム インストールを使用する場合は、リスナーを登録する方法を学習してください。

Then, configure the framework to catch App\Exception\ProductNotFoundException exceptions and convert them into 404 errors:

次に、App\Exception\ProductNotFoundException 例外をキャッチして 404 エラーに変換するようにフレームワークを構成します。

# config/packages/api_platform.yaml
api_platform:
    # ...
    exception_to_status:
        # The 4 following handlers are registered by default, keep those lines to prevent unexpected side effects
        Symfony\Component\Serializer\Exception\ExceptionInterface: 400 # Use a raw status code (recommended)
        ApiPlatform\Exception\InvalidArgumentException: !php/const Symfony\Component\HttpFoundation\Response::HTTP_BAD_REQUEST
        ApiPlatform\Exception\FilterValidationException: 400
        Doctrine\ORM\OptimisticLockException: 409

        # Validation exception
        ApiPlatform\Validator\Exception\ValidationException: !php/const Symfony\Component\HttpFoundation\Response::HTTP_UNPROCESSABLE_ENTITY

        # Custom mapping
        App\Exception\ProductNotFoundException: 404 # Here is the handler for our custom exception

Any type of Exception can be thrown, API Platform will convert it to a Symfony's HttpException (note that it means the exception will be flattened and lose all of its custom properties). The framework also takes care of serializing the error description according to the request format. For instance, if the API should respond in JSON-LD, the error will be returned in this format as well:

あらゆるタイプの例外をスローできます。API プラットフォームはそれを Symfony の HttpException に変換します (これは、例外がフラット化され、そのカスタム プロパティがすべて失われることを意味することに注意してください)。フレームワークは、リクエスト形式に従ってエラーの説明をシリアライズすることも処理します。たとえば、API が JSON-LD で応答する必要がある場合、エラーは次の形式でも返されます。

GET /products/1234

GET /製品/1234

{
  "@context": "/contexts/Error",
  "@type": "Error",
  "hydra:title": "An error occurred",
  "hydra:description": "The product \"1234\" does not exist."
}

Message Scope

Depending on the status code you use, the message may be replaced with a generic one in production to avoid leaking unwanted information. If your status code is >= 500 and < 600, the exception message will only be displayed in debug mode (dev and test). In production, a generic message matching the status code provided will be shown instead. If you are using an unofficial HTTP code, a general message will be displayed.

使用するステータス コードによっては、不要な情報が漏洩するのを避けるために、メッセージが本番環境で一般的なものに置き換えられる場合があります。ステータス コードが >= 500 かつ < 600 の場合、例外メッセージはデバッグ モードでのみ表示されます (dev およびテスト)。本番環境では、提供されたステータス コードに一致する一般的なメッセージが代わりに表示されます。非公式の HTTP コードを使用している場合は、一般的なメッセージが表示されます。

In any other cases, your exception message will be sent to end users.

それ以外の場合は、例外メッセージがエンド ユーザーに送信されます。

Fine-grained Configuration

The exceptionToStatus configuration can be set on resources and operations:

exceptionToStatus 構成は、リソースと操作に設定できます。

<?php
// api/src/Entity/Book.php
namespace App\Entity;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use App\Exception\ProductWasRemovedException;
use App\Exception\ProductNotFoundException;

#[ApiResource(
    exceptionToStatus: [ProductNotFoundException::class => 404]
    operations: [
        new Get(exceptionToStatus: [ProductWasRemovedException::class => 410]),
        new GetCollection(),
        new Post()
    ]
)]
class Book
{
    // ...
}

Exceptions mappings defined on operations take precedence over mappings defined on resources, which take precedence over the global config.

操作で定義された例外マッピングは、リソースで定義されたマッピングよりも優先され、リソースで定義されたマッピングはグローバル構成よりも優先されます。