diff --git a/src/JsonApi/Serializer/ErrorNormalizer.php b/src/JsonApi/Serializer/ErrorNormalizer.php index a9eba146f8..4875b28181 100644 --- a/src/JsonApi/Serializer/ErrorNormalizer.php +++ b/src/JsonApi/Serializer/ErrorNormalizer.php @@ -35,7 +35,7 @@ public function __construct(private ?NormalizerInterface $itemNormalizer = null) public function normalize(mixed $object, ?string $format = null, array $context = []): array { $jsonApiObject = $this->itemNormalizer->normalize($object, $format, $context); - $error = $jsonApiObject['data']['attributes']; + $error = $jsonApiObject['data']['attributes'] ?? []; $error['id'] = $jsonApiObject['data']['id']; if (isset($error['type'])) { $error['links'] = ['type' => $error['type']]; @@ -45,6 +45,11 @@ public function normalize(mixed $object, ?string $format = null, array $context $error['code'] = $object->getId(); } + // TODO: change this 5.x + // if (isset($error['status'])) { + // $error['status'] = (string) $error['status']; + // } + if (!isset($error['violations'])) { return ['errors' => [$error]]; } diff --git a/tests/Fixtures/TestBundle/ApiResource/JsonApiErrorTestResource.php b/tests/Fixtures/TestBundle/ApiResource/JsonApiErrorTestResource.php new file mode 100644 index 0000000000..a0899ac2f4 --- /dev/null +++ b/tests/Fixtures/TestBundle/ApiResource/JsonApiErrorTestResource.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\Tests\Fixtures\TestBundle\ApiResource; + +use ApiPlatform\Metadata\Exception\ItemNotFoundException; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\Operation; + +#[Get( + uriTemplate: '/jsonapi_error_test/{id}', + provider: [self::class, 'provide'], + formats: ['jsonapi' => ['application/vnd.api+json']], +)] +class JsonApiErrorTestResource +{ + public string $id; + public string $name; + + public static function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null + { + $id = $uriVariables['id'] ?? null; + + if ('existing' === $id) { + $resource = new self(); + $resource->id = $id; + $resource->name = 'Existing Resource'; + + return $resource; + } + + throw new ItemNotFoundException(\sprintf('Resource "%s" not found.', $id)); + } +} diff --git a/tests/Functional/JsonApiTest.php b/tests/Functional/JsonApiTest.php new file mode 100644 index 0000000000..9e90a391b2 --- /dev/null +++ b/tests/Functional/JsonApiTest.php @@ -0,0 +1,52 @@ + + * + * 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\Functional; + +use ApiPlatform\Symfony\Bundle\Test\ApiTestCase; +use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\JsonApiErrorTestResource; +use ApiPlatform\Tests\SetupClassResourcesTrait; + +class JsonApiTest extends ApiTestCase +{ + use SetupClassResourcesTrait; + protected static ?bool $alwaysBootKernel = false; + + /** + * @return class-string[] + */ + public static function getResources(): array + { + return [ + JsonApiErrorTestResource::class, + ]; + } + + public function testError(): void + { + self::createClient()->request('GET', '/jsonapi_error_test/nonexistent', [ + 'headers' => ['accept' => 'application/vnd.api+json'], + ]); + + $this->assertResponseStatusCodeSame(400); + $this->assertResponseHeaderSame('content-type', 'application/vnd.api+json; charset=utf-8'); + $this->assertJsonContains([ + 'errors' => [ + [ + 'status' => '400', + 'detail' => 'Resource "nonexistent" not found.', + ], + ], + ]); + } +}