Skip to content

Commit eb915e2

Browse files
authored
fix(jsonapi)!: drop non-spec type member from error objects (#8732)
* fix(jsonapi)!: drop non-spec type member from error objects JSON:API 1.1 forbids additional members on objects it defines, error objects only define links.type. The problem type URI was already exposed there, the top-level copy is removed. Refs #8704 * test(laravel): drop top-level type from json:api error expectation
1 parent bcb592a commit eb915e2

5 files changed

Lines changed: 65 additions & 3 deletions

File tree

‎src/JsonApi/Serializer/ErrorNormalizer.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public function normalize(mixed $data, ?string $format = null, array $context =
3939
$error['id'] = $jsonApiObject['data']['id'];
4040
if (isset($error['type'])) {
4141
$error['links'] = ['type' => $error['type']];
42+
unset($error['type']);
4243
}
4344

4445
if (!isset($error['code']) && method_exists($data, 'getId')) {
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <dunglas@gmail.com>
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\JsonApi\Tests\Serializer;
15+
16+
use ApiPlatform\JsonApi\Serializer\ErrorNormalizer;
17+
use PHPUnit\Framework\TestCase;
18+
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
19+
20+
class ErrorNormalizerTest extends TestCase
21+
{
22+
public function testTypeIsOnlyExposedUnderLinks(): void
23+
{
24+
$itemNormalizer = $this->createStub(NormalizerInterface::class);
25+
$itemNormalizer->method('normalize')->willReturn(['data' => [
26+
'id' => '/errors/500',
27+
'attributes' => ['type' => '/errors/500', 'title' => 'An error occurred', 'status' => 500],
28+
]]);
29+
30+
$errors = (new ErrorNormalizer($itemNormalizer))->normalize(new \Exception('boom'), 'jsonapi')['errors'];
31+
32+
$this->assertCount(1, $errors);
33+
$this->assertArrayNotHasKey('type', $errors[0]);
34+
$this->assertSame(['type' => '/errors/500'], $errors[0]['links']);
35+
$this->assertSame('500', $errors[0]['status']);
36+
}
37+
38+
public function testViolationsAreExposedWithoutTopLevelType(): void
39+
{
40+
$itemNormalizer = $this->createStub(NormalizerInterface::class);
41+
$itemNormalizer->method('normalize')->willReturn(['data' => [
42+
'id' => '/validation_errors/abc',
43+
'attributes' => [
44+
'type' => '/validation_errors/abc',
45+
'title' => 'Validation Failed',
46+
'status' => 422,
47+
'violations' => [['propertyPath' => 'name', 'message' => 'This value should not be blank.']],
48+
],
49+
]]);
50+
51+
$errors = (new ErrorNormalizer($itemNormalizer))->normalize(new \Exception('boom'), 'jsonapi')['errors'];
52+
53+
$this->assertCount(1, $errors);
54+
$this->assertArrayNotHasKey('type', $errors[0]);
55+
$this->assertArrayNotHasKey('violations', $errors[0]);
56+
$this->assertSame(['type' => '/validation_errors/abc/name'], $errors[0]['links']);
57+
$this->assertSame('This value should not be blank.', $errors[0]['detail']);
58+
}
59+
}

‎src/Laravel/Tests/JsonApiTest.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ public function testValidateJsonApi(): void
266266

267267
$this->assertArrayHasKey('id', $json['errors'][0]);
268268
$this->assertArrayHasKey('links', $json['errors'][0]);
269+
$this->assertArrayNotHasKey('type', $json['errors'][0]);
269270
$this->assertArrayHasKey('type', $json['errors'][0]['links']);
270271

271272
$response = $this->postJson(

‎src/Laravel/Tests/JsonProblemTest.php‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ public static function formatsProvider(): array
113113
[
114114
'id' => '401',
115115
'detail' => 'Unauthorized',
116-
'type' => 'about:blank',
117116
'title' => 'Error 401',
118117
'status' => 401,
119118
'code' => '401',

‎tests/Functional/JsonApi/ErrorTest.php‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ public function testRfc7807ErrorRendersJsonApiFormat(): void
9292
$this->assertSame('An error occurred', $body['errors'][0]['title']);
9393
$this->assertSame('400', $body['errors'][0]['status']);
9494
$this->assertArrayHasKey('detail', $body['errors'][0]);
95-
$this->assertArrayHasKey('type', $body['errors'][0]);
95+
$this->assertArrayNotHasKey('type', $body['errors'][0]);
96+
$this->assertArrayHasKey('type', $body['errors'][0]['links']);
9697
}
9798

9899
public function testNotFoundRouteRendersJsonApiFormat(): void
@@ -111,6 +112,7 @@ public function testNotFoundRouteRendersJsonApiFormat(): void
111112
$this->assertSame('An error occurred', $body['errors'][0]['title']);
112113
$this->assertSame('404', $body['errors'][0]['status']);
113114
$this->assertArrayHasKey('detail', $body['errors'][0]);
114-
$this->assertArrayHasKey('type', $body['errors'][0]);
115+
$this->assertArrayNotHasKey('type', $body['errors'][0]);
116+
$this->assertArrayHasKey('type', $body['errors'][0]['links']);
115117
}
116118
}

0 commit comments

Comments
 (0)