Validation

API Platform takes care of validating the data sent to the API by the client (usually user data entered through forms). By default, the framework relies on the powerful Symfony Validator Component for this task, but you can replace it with your preferred validation library such as the PHP filter extension if you want to.

API プラットフォームは、クライアントによって API に送信されたデータ (通常はフォームを通じて入力されたユーザー データ) を検証します。デフォルトでは、フレームワークはこのタスクのために強力な Symfony Validator Component に依存していますが、それを次のような好みの検証ライブラリに置き換えることができます。必要に応じて、PHP フィルター拡張機能として。

Validation screencast
Watch the Validation screencast

検証のスクリーンキャストを見る

Validating Submitted Data

Validating submitted data is as simple as adding Symfony's built-in constraints or custom constraints directly in classes marked with the #[ApiResource] attribute:

送信されたデータの検証は、Symfony の組み込み制約またはカスタム制約を #[ApiResource] 属性でマークされたクラスに直接追加するのと同じくらい簡単です。

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

use ApiPlatform\Metadata\ApiResource;
use App\Validator\Constraints\MinimalProperties; // A custom constraint
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert; // Symfony's built-in constraints

/**
 * A product.
 *
 */
#[ORM\Entity] 
#[ApiResource]
class Product
{
    #[ORM\Id, ORM\Column, ORM\GeneratedValue]
    private ?int $id = null;

    #[ORM\Column]
    #[Assert\NotBlank]
    public string $name;

    /**
     * @var string[] Describe the product
     */
    #[MinimalProperties]
    #[ORM\Column(type: 'json')] 
    public $properties;

    // Getters and setters...
}

And here is the custom MinimalProperties constraint and the related validator:

カスタムの MinimalProperties 制約と関連するバリデータは次のとおりです。

<?php
// api/src/Validator/Constraints/MinimalProperties.php

namespace App\Validator\Constraints;

use Symfony\Component\Validator\Constraint;

#[\Attribute]
class MinimalProperties extends Constraint
{
    public $message = 'The product must have the minimal properties required ("description", "price")';
}
<?php
// api/src/Validator/Constraints/MinimalPropertiesValidator.php

namespace App\Validator\Constraints;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

final class MinimalPropertiesValidator extends ConstraintValidator
{
    public function validate($value, Constraint $constraint): void
    {
        if (!array_diff(['description', 'price'], $value)) {
            $this->context->buildViolation($constraint->message)->addViolation();
        }
    }
}

If the data submitted by the client is invalid, the HTTP status code will be set to 422 Unprocessable Entity and the response's body will contain the list of violations serialized in a format compliant with the requested one. For instance, a validation error will look like the following if the requested format is JSON-LD (the default):

クライアントから送信されたデータが無効な場合、HTTP ステータス コードは 422 Unprocessable Entity に設定され、応答の本文には、要求されたものに準拠した形式でシリアル化された違反のリストが含まれます。たとえば、要求された形式が JSON-LD (デフォルト) の場合、validationerror は次のようになります。

{
  "@context": "/contexts/ConstraintViolationList",
  "@type": "ConstraintViolationList",
  "hydra:title": "An error occurred",
  "hydra:description": "properties: The product must have the minimal properties required (\"description\", \"price\")",
  "violations": [
    {
      "propertyPath": "properties",
      "message": "The product must have the minimal properties required (\"description\", \"price\")"
    }
  ]
}

Take a look at the Errors Handling guide to learn how API Platform converts PHP exceptions like validation errors to HTTP errors.

API プラットフォームが検証エラーなどの PHP 例外を HTTP エラーに変換する方法については、エラー処理ガイドをご覧ください。

Using Validation Groups

Without specific configuration, the default validation group is always used, but this behavior is customizable: the framework is able to leverage Symfony's validation groups.

特定の構成がなければ、デフォルトの検証グループが常に使用されますが、この動作はカスタマイズ可能です: フレームワークは Symfony の検証グループを活用できます。

You can configure the groups you want to use when the validation occurs directly through the ApiResource attribute:

ApiResource 属性を介して直接検証が行われるときに使用するグループを構成できます。

<?php
// api/src/Entity/Book.php

use ApiPlatform\Metadata\ApiResource;
use Symfony\Component\Validator\Constraints as Assert;

#[ApiResource(validationContext: ['groups' => ['a', 'b']])]
class Book
{
    #[Assert\NotBlank(groups: ['a'])]  
    public string $name;

    #[Assert\NotNull(groups: ['b'])] 
    public string $author;

    // ...
}

With the previous configuration, the validation groups a and b will be used when validation is performed.

前の構成では、検証が実行されるときに検証グループ a と b が使用されます。

Like for serialization groups, you can specify validation groups globally or on a per-operation basis.

シリアル化グループと同様に、検証グループをグローバルに、または操作ごとに指定できます。

Of course, you can use XML or YAML configuration format instead of attributes if you prefer.

もちろん、必要に応じて、属性の代わりに XML または YAML 構成形式を使用できます。

You may also pass in a group sequence in place of the array of group names.

グループ名の配列の代わりにグループ シーケンスを渡すこともできます。

Using Validation Groups on Operations

You can have different validation for each operation related to your resource.

リソースに関連する操作ごとに異なる検証を行うことができます。

<?php
// api/src/Entity/Book.php

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\Put;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\ApiResource;
use Symfony\Component\Validator\Constraints as Assert;

#[ApiResource]
#[Delete]
#[Get]
#[Put(validationContext: ['groups' => ['Default', 'putValidation']])]
#[GetCollection]
#[Post(validationContext: ['groups' => ['Default', 'postValidation']])]
class Book
{
    #[Assert\Uuid] 
    private $id;

    #[Assert\NotBlank(groups: ['postValidation'])] 
    public $name;

    #[Assert\NotNull]
    #[Assert\Length(min: 2, max: 50, groups: ['postValidation'])]
    #[Assert\Length(min: 2, max: 70, groups: ['putValidation'])] 
    public $author;

    // ...
}

With this configuration, there are three validation groups:

この構成では、3 つの検証グループがあります。

Default contains the constraints that belong to no other group.

デフォルトには、他のグループに属さない制約が含まれます。

postValidation contains the constraints on the name and author (length from 2 to 50) fields only.

postValidation には、name および author (長さ 2 から 50) フィールドのみに対する制約が含まれます。

putValidation contains the constraints on the author (length from 2 to 70) field only.

putValidation には、作成者 (長さ 2 から 70) フィールドのみの制約が含まれます。

Dynamic Validation Groups

If you need to dynamically determine which validation groups to use for an entity in different scenarios, just pass in a callable. The callback will receive the entity object as its first argument, and should return an array of group names or a group sequence.

さまざまなシナリオでエンティティに使用する検証グループを動的に決定する必要がある場合は、callable を渡すだけです。コールバックはエンティティ オブジェクトを最初の引数として受け取り、グループ名の配列またはグループ シーケンスを返す必要があります。

In the following example, we use a static method to return the validation groups:

次の例では、静的メソッドを使用して検証グループを返します。

<?php
// api/src/Entity/Book.php

use ApiPlatform\Metadata\ApiResource;
use Symfony\Component\Validator\Constraints as Assert;

#[ApiResource(
    validationContext: ['groups' => [Book::class, 'validationGroups']
)]
class Book
{
    /**
     * Return dynamic validation groups.
     *
     * @param self $book Contains the instance of Book to validate.
     *
     * @return string[]
     */
    public static function validationGroups(self $book)
    {
        return ['a'];
    }

    #[Assert\NotBlank(groups: ['a'])] 
    public $name;

    #[Assert\NotNull(groups: ['b'])] 
    public $author;

    // ...
}

Alternatively, you can use a service to retrieve the groups to use:

または、サービスを使用して、使用するグループを取得できます。

<?php
// api/src/Validator/AdminGroupsGenerator.php

namespace App\Validator;

use ApiPlatform\Symfony\Validator\ValidationGroupsGeneratorInterface;
use App\Entity\Book;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;

final class AdminGroupsGenerator implements ValidationGroupsGeneratorInterface
{
    private $authorizationChecker;

    public function __construct(AuthorizationCheckerInterface $authorizationChecker)
    {
        $this->authorizationChecker = $authorizationChecker;
    }

    /**
     * {@inheritdoc}
     */
    public function __invoke($book): array
    {
        assert($book instanceof Book);

        return $this->authorizationChecker->isGranted('ROLE_ADMIN', $book) ? ['a', 'b'] : ['a'];
    }
}

This class selects the groups to apply based on the role of the current user: if the current user has the ROLE_ADMIN role, groups a and b are returned. In other cases, just a is returned.

このクラスは、現在のユーザーの役割に基づいて適用するグループを選択します。現在のユーザーが ROLE_ADMIN 役割を持っている場合、グループ a と b が返されます。それ以外の場合は、 a のみが返されます。

This class is automatically registered as a service thanks to the autowiring feature of the Symfony DependencyInjection component.

このクラスは、Symfony DependencyInjection コンポーネントの自動配線機能により、サービスとして自動的に登録されます。

Then, configure the entity class to use this service to retrieve validation groups:

次に、このサービスを使用して検証グループを取得するようにエンティティ クラスを構成します。

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

use ApiPlatform\Metadata\ApiResource;
use App\Validator\AdminGroupsGenerator;
use Symfony\Component\Validator\Constraints as Assert;

#[ApiResource(validationContext: ['groups' => AdminGroupsGenerator::class])
class Book
{
    #[Assert\NotBlank(groups: ['a'])] 
    public $name;

    #[Assert\NotNull(groups: ['b'])] 
    public $author;

    // ...
}

Sequential Validation Groups

If you need to specify the order in which your validation groups must be tested against, you can use a group sequence. First, you need to create your sequenced group.

検証グループをテストする順序を指定する必要がある場合は、グループ シーケンスを使用できます。最初に、シーケンス グループを作成する必要があります。

<?php
namespace App\Validator;

use Symfony\Component\Validator\Constraints\GroupSequence;

class MySequencedGroup
{
    public function __invoke()
    {
        return new GroupSequence(['first', 'second']); // now, no matter which is first in the class declaration, it will be tested in this order.
    }
}

Just creating the class is not enough because Symfony does not see this service as being used. Therefore to prevent the service to be removed, you need to enforce it to be public.

Symfony はこのサービスが使用されていると見なさないため、クラスを作成するだけでは十分ではありません。したがって、サービスが削除されないようにするには、強制的に公開する必要があります。

# api/config/services.yaml
services:
    App\Validator\MySequencedGroup: ~
        public: true

And then, you need to use your class as a validation group.

次に、クラスを検証グループとして使用する必要があります。

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

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Post;
use App\Validator\One; // classic custom constraint
use App\Validator\Two; // classic custom constraint
use App\Validator\MySequencedGroup; // the sequence group to use
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ApiResource]
#[Post(validationContext: ['groups' => MySequencedGroup::class])]
class Greeting
{
    #[ORM\Id, ORM\Column, ORM\GeneratedValue]
    private ?int $id = null;

    /**
     * @var A nice person
     * 
     * I want this "second" validation to be executed after the "first" one even though I wrote them in this order.
     * @One(groups={"second"})
     * @Two(groups={"first"})
     */
    #[ORM\Column]
    public string $name = '';

    public function getId(): int
    {
        return $this->id;
    }
}

Validating Delete Operations

By default, validation rules that are specified on the API resource are not evaluated during DELETE operations. You need to trigger the validation in your code, if needed.

デフォルトでは、API リソースで指定された検証規則は、DELETE 操作中に評価されません。必要に応じて、コードで検証をトリガーする必要があります。

Assume that you have the following entity that uses a custom delete validator:

カスタム削除バリデータを使用する次のエンティティがあるとします。

<?php
// api/src/Entity/MyEntity.php

namespace App\Entity;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Delete;
use App\State\MyEntityRemoveProcessor;
use App\Validator\AssertCanDelete;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
#[ApiResource(
    operations: [
        new Delete(validationContext: ['groups' => ['deleteValidation']], processor: MyEntityRemoveProcessor::class)
    ]
)]
#[AssertCanDelete(groups: ['deleteValidation'])]
class MyEntity
{
    #[ORM\Id, ORM\Column, ORM\GeneratedValue]
    private ?int $id = null;

    #[ORM\Column]
    public string $name = '';
}

Create a processor, which receives the default processor, where you will trigger the validation:

検証をトリガーするデフォルトのプロセッサを受け取るプロセッサを作成します。

<?php
// api/src/State/MyEntityRemoveProcessor.php

namespace App\State;

use ApiPlatform\Doctrine\Common\State\RemoveProcessor as DoctrineRemoveProcessor;
use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\Validator\ValidatorInterface;
use App\Entity\MyEntity;

class MyEntityRemoveProcessor implements ProcessorInterface
{
    public function __construct(
        private DoctrineRemoveProcessor $doctrineProcessor,
        private ValidatorInterface $validator,
    ) {
    }

    public function process($data, Operation $operation, array $uriVariables = [], array $context = [])
    {
        $this->validator->validate($data, ['groups' => ['deleteValidation']]);
        $this->doctrineProcessor->process($data, $operation, $uriVariables, $context);
    }
}

Error Levels and Payload Serialization

As stated in the Symfony documentation, you can use the payload field to define error levels. You can retrieve the payload field by setting the serialize_payload_fields to an empty array in the API Platform config:

Symfony のドキュメントに記載されているように、ペイロード フィールドを使用してエラー レベルを定義できます。ペイロード フィールドを取得するには、API プラットフォーム構成で serialize_payload_fields を空の配列に設定します。

# api/config/packages/api_platform.yaml

api_platform:
    validator:
        serialize_payload_fields: ~

Then, the serializer will return all payload values in the error response.

次に、シリアライザーはエラー応答ですべてのペイロード値を返します。

If you want to serialize only some payload fields, define them in the config like this:

一部のペイロード フィールドのみをシリアライズする場合は、次のように設定で定義します。

# api/config/packages/api_platform.yaml

api_platform:
    validator:
        serialize_payload_fields: [ severity, anotherPayloadField ]

In this example, only severity and anotherPayloadField will be serialized.

この例では、severity と anotherPayloadField のみがシリアル化されます。

Validation on Collection Relations

Use the Valid constraint.

Valid 制約を使用します。

Note: this is related to the collection relation denormalization. You may have an issue when trying to validate a relation representing a Doctrine's ArrayCollection (toMany). Fix the denormalization using the property getter. Return an array instead of an ArrayCollection with $collectionRelation->getValues(). Then, define your validation on the getter instead of the property.

注: これはコレクション関係の非正規化に関連しています。Doctrine の ArrayCollection (toMany) を表す関係を検証しようとすると、問題が発生する可能性があります。プロパティ ゲッターを使用して非正規化を修正します。 $collectionRelation->getValues() で ArrayCollection の代わりに配列を返します。次に、プロパティではなくゲッターで検証を定義します。

For example:

例えば:

<getter property="cars">
    <constraint name="Valid"/>
</getter>
<?php
// api/src/Entity/Brand.php
namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;

final class Brand
{
    // ...

    public function __construct()
    {
        $this->cars = new ArrayCollection();
    }

    #[Assert\Valid]
    public function getCars()
    {
        return $this->cars->getValues();
    }
}

Open Vocabulary Generated from Validation Metadata

API Platform automatically detects Symfony's built-in validators and generates schema.org IRI metadata accordingly. This allows for rich clients such as the Admin component to infer the field types for most basic use cases.

API プラットフォームは、Symfony の組み込みバリデーターを自動的に検出し、それに応じて schema.org IRI メタデータを生成します。これにより、管理コンポーネントなどのリッチ クライアントは、最も基本的なユース ケースのフィールド タイプを推測できます。

The following validation constraints are covered:

次の検証制約がカバーされています。

Constraints Vocabulary
Url https://schema.org/url
Email https://schema.org/email
Uuid https://schema.org/identifier
CardScheme https://schema.org/identifier
Bic https://schema.org/identifier
Iban https://schema.org/identifier
Date https://schema.org/Date
DateTime https://schema.org/DateTime
Time https://schema.org/Time
Image https://schema.org/image
File https://schema.org/MediaObject
Currency https://schema.org/priceCurrency
Isbn https://schema.org/isbn
Issn https://schema.org/issn

Specification property restrictions

API Platform generates specification property restrictions based on Symfony’s built-in validator.

API プラットフォームは、Symfony の組み込みバリデーターに基づいて仕様プロパティの制限を生成します。

For example, from Regex constraint API Platform builds pattern restriction.

たとえば、Regex 制約 API Platform ビルド パターン制限から。

For building custom property schema based on custom validation constraints you can create a custom class for generating property scheme restriction.

カスタム検証制約に基づいてカスタム プロパティ スキーマを構築するために、プロパティ スキーム制限を生成するためのカスタム クラスを作成できます。

To create property schema, you have to implement the PropertySchemaRestrictionMetadataInterface. This interface defines only 2 methods:

プロパティ スキーマを作成するには、PropertySchemaRestrictionMetadataInterface を実装する必要があります。このインターフェイスは 2 つのメソッドのみを定義します。

  • create: to create property schema
    create: プロパティ スキーマを作成します。
  • supports: to check whether the property and constraint is supported
    supports: プロパティと制約がサポートされているかどうかを確認します

Here is an implementation example:

実装例を次に示します。

namespace App\PropertySchemaRestriction;

use ApiPlatform\Metadata\ApiProperty;
use Symfony\Component\Validator\Constraint;
use App\Validator\CustomConstraint;

final class CustomPropertySchemaRestriction implements PropertySchemaRestrictionMetadataInterface
{
    public function supports(Constraint $constraint, ApiProperty $propertyMetadata): bool
    {
        return $constraint instanceof CustomConstraint;
    }

    public function create(Constraint $constraint, ApiProperty $propertyMetadata): array 
    {
      // your logic to create property schema restriction based on constraint
      return $restriction;
    }
}

If you use a custom dependency injection configuration, you need to register the corresponding service and add the api_platform.metadata.property_schema_restriction tag. The priority attribute can be used for service ordering.

カスタム依存性注入構成を使用する場合は、対応するサービスを登録し、api_platform.metadata.property_schema_restriction タグを追加する必要があります。優先順位属性は、サービスの順序付けに使用できます。

```yaml

```yaml

api/config/services.yaml

services: # ... 'App\PropertySchemaRestriction\CustomPropertySchemaRestriction': ~ # Uncomment only if autoconfiguration is disabled #tags: [ 'api_platform.metadata.property_schema_restriction' ]

services:# ...'App\PropertySchemaRestriction\CustomPropertySchemaRestriction': ~# 自動構成が無効な場合のみコメント解除#tags: [ 'api_platform.metadata.property_schema_restriction' ]