Api Platform conference
Register now
Guides
Guide

Delete operation with validation

validation expert
Let’s add a custom Constraint.
// src/App/Validator.php namespace App\Validator; use Symfony\Component\Validator\Constraint; #[\Attribute] class AssertCanDelete extends Constraint {  public string $message = 'For whatever reason we denied removal of this data.';  public string $mode = 'strict';  public function getTargets(): string  {  return self::CLASS_CONSTRAINT;  } }
And a custom validator following Symfony’s naming conventions.
// src/App/Validator.php namespace App\Validator; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; class AssertCanDeleteValidator extends ConstraintValidator {  public function validate(mixed $value, Constraint $constraint): void  {  $this->context->buildViolation($constraint->message)->addViolation();  } }  // src/App/Entity.php namespace App\Entity; use ApiPlatform\Metadata\Delete; use ApiPlatform\Validator\Exception\ValidationException; use App\Validator\AssertCanDelete; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] #[Delete( 
By default, validation is not triggered on a DELETE operation, let’s activate it.
 validate: true,
Just as with serialization we can add validation groups.
 validationContext: ['groups' => ['deleteValidation']],  exceptionToStatus: [ValidationException::class => 403] )]
Here we use the previously created constraint on the class directly.
#[AssertCanDelete(groups: ['deleteValidation'])] class Book {  #[ORM\Id, ORM\Column, ORM\GeneratedValue]  private ?int $id = null;  #[ORM\Column]  public string $title = '';  public function getId()  {  return $this->id;  } }  // src/App/Playground.php namespace App\Playground; use Symfony\Component\HttpFoundation\Request; function request(): Request {  return Request::create(uri: '/books/1', method: 'DELETE', server: ['CONTENT_TYPE' => 'application/ld+json']); }  // src/App/Fixtures.php namespace App\Fixtures; use App\Entity\Book; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Persistence\ObjectManager; use function Zenstruck\Foundry\anonymous; use function Zenstruck\Foundry\faker; use function Zenstruck\Foundry\repository; final class BookFixtures extends Fixture {  public function load(ObjectManager $manager): void  {  $bookFactory = anonymous(Book::class);  if (repository(Book::class)->count()) {  return;  }  $bookFactory->many(10)->create(  fn () => [  'title' => faker()->name(),  ]  );  } }  // src/DoctrineMigrations.php namespace DoctrineMigrations; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; final class Migration extends AbstractMigration {  public function up(Schema $schema): void  {  $this->addSql('CREATE TABLE book (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, title VARCHAR(255) NOT NULL)');  } }

You can also help us improve this guide.

Made with love by

Les-Tilleuls.coop can help you design and develop your APIs and web projects, and train your teams in API Platform, Symfony, Next.js, Kubernetes and a wide range of other technologies.

Learn more

Copyright © 2023 Kévin Dunglas

Sponsored by Les-Tilleuls.coop