diff --git a/core/modules/rest/src/Plugin/rest/resource/EntityResourceValidationTrait.php b/core/modules/rest/src/Plugin/rest/resource/EntityResourceValidationTrait.php index 50c7e1c..d3779eb 100644 --- a/core/modules/rest/src/Plugin/rest/resource/EntityResourceValidationTrait.php +++ b/core/modules/rest/src/Plugin/rest/resource/EntityResourceValidationTrait.php @@ -2,11 +2,9 @@ namespace Drupal\rest\Plugin\rest\resource; -use Drupal\Component\Render\PlainTextOutput; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\FieldableEntityInterface; -use Drupal\rest\Exception\EntityValidationException; -use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException; +use Drupal\serialization\Exception\EntityValidationException; /** * @internal @@ -20,7 +18,7 @@ * @param \Drupal\Core\Entity\EntityInterface $entity * The entity to validate. * - * @throws \Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException + * @throws \Drupal\serialization\Exception\EntityValidationException * If validation errors are found. */ protected function validate(EntityInterface $entity) { @@ -35,7 +33,7 @@ protected function validate(EntityInterface $entity) { $violations->filterByFieldAccess(); if ($violations->count() > 0) { - throw new EntityValidationException($violations); + throw new EntityValidationException($violations, 'Validation of the {$entity->getEntityTypeId()} entity failed'); } } diff --git a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php index ebb03e2..82ed3a9 100644 --- a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php +++ b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php @@ -683,7 +683,15 @@ public function testPost() { $response = $this->request('POST', $url, $request_options); $label_field = $this->entity->getEntityType()->hasKey('label') ? $this->entity->getEntityType()->getKey('label') : static::$labelFieldName; $label_field_capitalized = ucfirst($label_field); - $this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\n$label_field: $label_field_capitalized: this field cannot hold more than 1 values.\n", $response); + + $entity_type_id = static::$entityTypeId; + $error = [ + 'message' => "Validation of the $entity_type_id entity failed", + 'errors' => [ + $label_field => "$label_field_capitalized: this field cannot hold more than 1 values.", + ], + ]; + $this->assertResourceErrorResponse(422, json_encode($error), $response); $request_options[RequestOptions::BODY] = $parseable_invalid_request_body_2; @@ -691,7 +699,13 @@ public function testPost() { // DX: 422 when invalid entity: UUID field too long. $response = $this->request('POST', $url, $request_options); - $this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nuuid.0.value: UUID: may not be longer than 128 characters.\n", $response); + $error = [ + 'message' => "Validation of the $entity_type_id entity failed", + 'errors' => [ + 'uuid.0.value' => 'UUID: may not be longer than 128 characters.', + ], + ]; + $this->assertResourceErrorResponse(422, json_encode($error), $response); $request_options[RequestOptions::BODY] = $parseable_invalid_request_body_3; diff --git a/core/modules/serialization/serialization.services.yml b/core/modules/serialization/serialization.services.yml index 3e47b00..3d74e19 100644 --- a/core/modules/serialization/serialization.services.yml +++ b/core/modules/serialization/serialization.services.yml @@ -64,6 +64,10 @@ services: class: Drupal\serialization\Normalizer\TypedDataNormalizer tags: - { name: normalizer } + serializer.normalizer.entity_validation_exception: + class: \Drupal\serialization\Normalizer\EntityValidationExceptionNormalizer + tags: + - { name: normalizer } serializer.encoder.json: class: Drupal\serialization\Encoder\JsonEncoder tags: diff --git a/core/modules/serialization/src/EventSubscriber/DefaultExceptionSubscriber.php b/core/modules/serialization/src/EventSubscriber/DefaultExceptionSubscriber.php index a1e7bad..5be6c33 100644 --- a/core/modules/serialization/src/EventSubscriber/DefaultExceptionSubscriber.php +++ b/core/modules/serialization/src/EventSubscriber/DefaultExceptionSubscriber.php @@ -62,13 +62,18 @@ protected static function getPriority() { * The event to process. */ public function on4xx(GetResponseForExceptionEvent $event) { - /** @var \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface $exception */ + /** @var \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface|\Exception $exception */ $exception = $event->getException(); $request = $event->getRequest(); $format = $request->getRequestFormat(); - $content = ['message' => $event->getException()->getMessage()]; - $encoded_content = $this->serializer->serialize($content, $format); + + if ($this->serializer->supportsNormalization($exception, $format)) { + $encoded_content = $this->serializer->serialize($exception, $format); + } + else { + $encoded_content = ['message' => $exception->getMessage()]; + } $headers = $exception->getHeaders(); // Add the MIME type from the request to send back in the header. diff --git a/core/modules/rest/src/Exception/EntityValidationException.php b/core/modules/serialization/src/Exception/EntityValidationException.php similarity index 73% rename from core/modules/rest/src/Exception/EntityValidationException.php rename to core/modules/serialization/src/Exception/EntityValidationException.php index b0b2255..caf5de7 100644 --- a/core/modules/rest/src/Exception/EntityValidationException.php +++ b/core/modules/serialization/src/Exception/EntityValidationException.php @@ -1,10 +1,18 @@ getViolations(); + $result['message'] = $object->getMessage(); - $result = array_reduce(iterator_to_array($violations), function (array $carry, ConstraintViolation $violation) { + // Group violations by field path. + $result['errors'] = array_reduce(iterator_to_array($violations), function (array $carry, ConstraintViolation $violation) { $carry[$violation->getPropertyPath()][] = PlainTextOutput::renderFromHtml($violation->getMessage()); return $carry; }, []); + } + return $result; } diff --git a/core/tests/README.md b/core/tests/README.md index 566fa23..a454c7e 100644 --- a/core/tests/README.md +++ b/core/tests/README.md @@ -1,4 +1,4 @@ -# Running tests +# Runnin testt ## Functional tests