diff --git a/features/main/validation.feature b/features/main/validation.feature
index e0e29dfe181..170c4c51a27 100644
--- a/features/main/validation.feature
+++ b/features/main/validation.feature
@@ -157,3 +157,34 @@ Feature: Using validations groups
]
}
"""
+
+ @!mongodb
+ Scenario: Get violations constraints
+ When I add "Accept" header equal to "application/json"
+ And I add "Content-Type" header equal to "application/json"
+ And I send a "POST" request to "/issue5912s" with body:
+ """
+ {
+ "title": ""
+ }
+ """
+ Then the response status code should be 422
+ And the response should be in JSON
+ And the JSON should be equal to:
+ """
+ {
+ "status": 422,
+ "violations": [
+ {
+ "propertyPath": "title",
+ "message": "This value should not be blank.",
+ "code": "c1051bb4-d103-4f74-8988-acbcafc7fdc3"
+ }
+ ],
+ "detail": "title: This value should not be blank.",
+ "type": "/validation_errors/c1051bb4-d103-4f74-8988-acbcafc7fdc3",
+ "title": "An error occurred"
+ }
+ """
+ And the header "Content-Type" should be equal to "application/problem+json; charset=utf-8"
+
diff --git a/src/Symfony/Bundle/Resources/config/symfony/validator.xml b/src/Symfony/Bundle/Resources/config/symfony/validator.xml
index 0f8eb782224..cf5c9f92a9c 100644
--- a/src/Symfony/Bundle/Resources/config/symfony/validator.xml
+++ b/src/Symfony/Bundle/Resources/config/symfony/validator.xml
@@ -31,6 +31,14 @@
+
+
+ %api_platform.validator.serialize_payload_fields%
+
+
+
+
+
diff --git a/src/Symfony/Validator/Exception/ValidationException.php b/src/Symfony/Validator/Exception/ValidationException.php
index 9d46283ebb7..ef80badd00d 100644
--- a/src/Symfony/Validator/Exception/ValidationException.php
+++ b/src/Symfony/Validator/Exception/ValidationException.php
@@ -19,6 +19,7 @@
use ApiPlatform\Metadata\Exception\ProblemExceptionInterface;
use ApiPlatform\Metadata\Util\CompositeIdentifierParser;
use ApiPlatform\Validator\Exception\ValidationException as BaseValidationException;
+use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Annotation\SerializedName;
use Symfony\Component\Validator\ConstraintViolationListInterface;
@@ -50,7 +51,7 @@
],
graphQlOperations: []
)]
-final class ValidationException extends BaseValidationException implements ConstraintViolationListAwareExceptionInterface, \Stringable, ProblemExceptionInterface
+final class ValidationException extends BaseValidationException implements ConstraintViolationListAwareExceptionInterface, \Stringable, ProblemExceptionInterface, HttpExceptionInterface
{
private int $status = 422;
@@ -154,4 +155,14 @@ public function __toString(): string
return $message;
}
+
+ public function getStatusCode(): int
+ {
+ return $this->status;
+ }
+
+ public function getHeaders(): array
+ {
+ return [];
+ }
}
diff --git a/src/Symfony/Validator/Serializer/ConstraintViolationListNormalizer.php b/src/Symfony/Validator/Serializer/ConstraintViolationListNormalizer.php
new file mode 100644
index 00000000000..46fb21cf55c
--- /dev/null
+++ b/src/Symfony/Validator/Serializer/ConstraintViolationListNormalizer.php
@@ -0,0 +1,44 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace ApiPlatform\Symfony\Validator\Serializer;
+
+use ApiPlatform\Serializer\AbstractConstraintViolationListNormalizer;
+use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
+
+/**
+ * Converts {@see \Symfony\Component\Validator\ConstraintViolationListInterface} the API Problem spec (RFC 7807).
+ *
+ * @author Kévin Dunglas
+ */
+final class ConstraintViolationListNormalizer extends AbstractConstraintViolationListNormalizer
+{
+ public const FORMAT = 'json';
+
+ private array $defaultContext = [];
+
+ public function __construct(array $serializePayloadFields = null, NameConverterInterface $nameConverter = null, array $defaultContext = [])
+ {
+ parent::__construct($serializePayloadFields, $nameConverter);
+
+ $this->defaultContext = array_merge($this->defaultContext, $defaultContext);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function normalize(mixed $object, string $format = null, array $context = []): array
+ {
+ return $this->getViolations($object);
+ }
+}
diff --git a/tests/Fixtures/TestBundle/Entity/Issue5912/Dummy.php b/tests/Fixtures/TestBundle/Entity/Issue5912/Dummy.php
new file mode 100644
index 00000000000..46c50d630aa
--- /dev/null
+++ b/tests/Fixtures/TestBundle/Entity/Issue5912/Dummy.php
@@ -0,0 +1,32 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity\Issue5912;
+
+use ApiPlatform\Metadata\ApiResource;
+use ApiPlatform\Metadata\NotExposed;
+use ApiPlatform\Metadata\Post;
+use Symfony\Component\Validator\Constraints\NotBlank;
+
+#[ApiResource(
+ shortName: 'Issue5912',
+ operations: [
+ new NotExposed(),
+ new Post(),
+ ]
+)]
+class Dummy
+{
+ #[NotBlank]
+ public string $title;
+}