how throw a custom exception in JSONAPI?
-
02-03-2021 - |
Question
In D8 i'm trying to throw custom exceptions for extra validations that i need to do before the content is saved in my custom entity, but when i do the validations in the presave method and throw a normal Exception:
public function preSave(EntityStorageInterface $storage) {
throw new \Exception("The content is duplicated", 409);
}
The response of JSONAPI is code 500 Internal Server Error and the response:
{
"jsonapi": {
"version": "1.0",
"meta": {
"links": {
"self": {
"href": "http://jsonapi.org/format/1.0/"
}
}
}
},
"errors": [
{
"title": "Internal Server Error",
"status": "500",
"detail": "The content is duplicated",
"links": {
"via": {
"href": "http://site.docksal/jsonapi/content_entity/content_entity"
},
"info": {
"href": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.1"
}
}
}
]
}
how can i control de error Code, title, status and detail.
Solution
thanks @4k4, I solved it using customs constraints in my custom entity, JSONAPI mapping well the error and the admin UI works perfectly with that.
like @kiamlaluno said, i try to explain the solution using constraints:
I want to response in the JSONAPI Request that the content is already exists but with a different code, no 500. So when i use constraints i can validate if content already exist or not and response if is a valid request (TRUE / FALSE), this constraints works in the JSONAPI Responses and in the Drupal Admin UI.
So you need to define the constraint in the folder "my_module/src/Plugin/Validation/Constraint" and create 2 files, for my example i need that the content is unique. so my files are:
UniqueProfileContentConstraint.php
<?php
namespace Drupal\my_module\Plugin\Validation\Constraint;
use Symfony\Component\Validator\Constraint;
/**
* Plugin implementation of the 'unique_entry_constraint'.
*
* @Constraint(
* id = "unique_profile_content_constraint",
* label = @Translation("Unique entry constraint", context = "Validation"),
* )
*/
class UniqueProfileContentConstraint extends Constraint
{
// The message that will be shown if the value is not unique.
public $notUnique = 'This content already exists';
}
And the validator:
UniqueProfileContentConstraintValidator.php
<?php
namespace Drupal\ztv_content\Plugin\Validation\Constraint;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
/**
* Validates the UniqueInteger constraint.
*/
class UniqueProfileContentConstraintValidator extends ConstraintValidator
{
/**
* {@inheritdoc}
*/
public function validate($entity, Constraint $constraint) {
// Next check if the value is unique.
if (!$this->isUnique($entity)) {
$this->context->addViolation($constraint->notUnique);
}
}
private function isUnique($entity)
{
if ($entity->isNew()) {
$query = \Drupal::entityQuery('profile_content_entity')
->condition('profile_id', $entity->get('profile_id')->getString())
->condition('video_id', $entity->get('video_id')->value);
$storageContent = $query->execute();
if ($storageContent) {
return FALSE;
}
return TRUE;
}
}
}
And finally in the Entity annotation you need to add the id of your constraint:
* constraints = {
* "unique_profile_content_constraint" = {}
* }
* )
*/