Skip to content

Commit 1afec8c

Browse files
committed
suggest another approach
1 parent 5938c2b commit 1afec8c

File tree

5 files changed

+78
-70
lines changed

5 files changed

+78
-70
lines changed

features/jsonapi/errors.feature

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,3 @@ Feature: JSON API error handling
6161
And the JSON node "errors[0].status" should be equal to 404
6262
And the JSON node "errors[0].detail" should exist
6363
And the JSON node "errors[0].type" should exist
64-
65-
Scenario: Get a proper error when ItemNotFoundException is thrown from a provider
66-
When I send a "GET" request to "/jsonapi_error_test/nonexistent"
67-
Then the response status code should be 404
68-
And the response should be in JSON
69-
And the header "Content-Type" should be equal to "application/vnd.api+json; charset=utf-8"
70-
And the JSON node "errors" should exist
71-
And the JSON node "errors[0].status" should exist
72-
And the JSON node "errors[0].title" should exist
73-
And the JSON node "errors[0].id" should exist

src/JsonApi/Serializer/ErrorNormalizer.php

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,7 @@ public function __construct(private ?NormalizerInterface $itemNormalizer = null)
3535
public function normalize(mixed $object, ?string $format = null, array $context = []): array
3636
{
3737
$jsonApiObject = $this->itemNormalizer->normalize($object, $format, $context);
38-
39-
if (!isset($jsonApiObject['data']['attributes'])) {
40-
return ['errors' => [[
41-
'id' => $jsonApiObject['data']['id'] ?? uniqid('error_', true),
42-
'status' => (string) (method_exists($object, 'getStatusCode') ? $object->getStatusCode() : 500),
43-
'title' => method_exists($object, 'getMessage') ? $object->getMessage() : 'An error occurred',
44-
]]];
45-
}
46-
47-
$error = $jsonApiObject['data']['attributes'];
38+
$error = $jsonApiObject['data']['attributes'] ?? [];
4839
$error['id'] = $jsonApiObject['data']['id'];
4940
if (isset($error['type'])) {
5041
$error['links'] = ['type' => $error['type']];
@@ -54,6 +45,10 @@ public function normalize(mixed $object, ?string $format = null, array $context
5445
$error['code'] = $object->getId();
5546
}
5647

48+
if (isset($error['status'])) {
49+
$error['status'] = (string) $error['status'];
50+
}
51+
5752
if (!isset($error['violations'])) {
5853
return ['errors' => [$error]];
5954
}

tests/Fixtures/TestBundle/ApiResource/JsonApiErrorTestResource.php

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,32 @@
1313

1414
namespace ApiPlatform\Tests\Fixtures\TestBundle\ApiResource;
1515

16-
use ApiPlatform\Metadata\ApiProperty;
17-
use ApiPlatform\Metadata\ApiResource;
16+
use ApiPlatform\Metadata\Exception\ItemNotFoundException;
1817
use ApiPlatform\Metadata\Get;
19-
use ApiPlatform\Tests\Fixtures\TestBundle\State\JsonApiErrorTestProvider;
20-
21-
#[ApiResource(
22-
operations: [
23-
new Get(
24-
uriTemplate: '/jsonapi_error_test/{id}',
25-
provider: JsonApiErrorTestProvider::class,
26-
),
27-
],
18+
use ApiPlatform\Metadata\Operation;
19+
20+
#[Get(
21+
uriTemplate: '/jsonapi_error_test/{id}',
22+
provider: [self::class, 'provide'],
2823
formats: ['jsonapi' => ['application/vnd.api+json']],
2924
)]
3025
class JsonApiErrorTestResource
3126
{
32-
#[ApiProperty(identifier: true)]
3327
public string $id;
34-
3528
public string $name;
29+
30+
public static function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
31+
{
32+
$id = $uriVariables['id'] ?? null;
33+
34+
if ('existing' === $id) {
35+
$resource = new self();
36+
$resource->id = $id;
37+
$resource->name = 'Existing Resource';
38+
39+
return $resource;
40+
}
41+
42+
throw new ItemNotFoundException(\sprintf('Resource "%s" not found.', $id));
43+
}
3644
}

tests/Fixtures/TestBundle/State/JsonApiErrorTestProvider.php

Lines changed: 0 additions & 37 deletions
This file was deleted.

tests/Functional/JsonApiTest.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Tests\Functional;
15+
16+
use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
17+
use ApiPlatform\Tests\Fixtures\TestBundle\ApiResource\JsonApiErrorTestResource;
18+
use ApiPlatform\Tests\SetupClassResourcesTrait;
19+
20+
class JsonApiTest extends ApiTestCase
21+
{
22+
use SetupClassResourcesTrait;
23+
protected static ?bool $alwaysBootKernel = false;
24+
25+
/**
26+
* @return class-string[]
27+
*/
28+
public static function getResources(): array
29+
{
30+
return [
31+
JsonApiErrorTestResource::class,
32+
];
33+
}
34+
35+
public function testError(): void
36+
{
37+
self::createClient()->request('GET', '/jsonapi_error_test/nonexistent', [
38+
'headers' => ['accept' => 'application/vnd.api+json'],
39+
]);
40+
41+
$this->assertResponseStatusCodeSame(400);
42+
$this->assertResponseHeaderSame('content-type', 'application/vnd.api+json; charset=utf-8');
43+
$this->assertJsonContains([
44+
'errors' => [
45+
[
46+
'status' => '400',
47+
'detail' => 'Resource "nonexistent" not found.',
48+
],
49+
],
50+
]);
51+
}
52+
}

0 commit comments

Comments
 (0)