From 8254e07a12866548b2326d4566e7b488f6a34ffc Mon Sep 17 00:00:00 2001 From: Maxcastel Date: Tue, 8 Sep 2026 14:52:24 +0200 Subject: [PATCH] feat(jsonapi)!: default use_iri_as_id to false --- CHANGELOG.md | 6 +++++ src/Laravel/ApiPlatformProvider.php | 2 +- src/Laravel/Tests/JsonApiTest.php | 2 ++ src/Laravel/Tests/JsonProblemTest.php | 2 +- src/Laravel/config/api-platform.php | 6 ++--- .../ApiPlatformExtension.php | 4 ---- .../DependencyInjection/Configuration.php | 4 ++-- ...tionTest.php => JsonApiUseIriAsIdTest.php} | 22 +++++++++---------- tests/Fixtures/app/config/config_common.yml | 2 ++ tests/Functional/JsonApi/IriModeTest.php | 4 ++-- .../DependencyInjection/ConfigurationTest.php | 2 +- 11 files changed, 30 insertions(+), 26 deletions(-) rename src/Symfony/Tests/Bundle/DependencyInjection/{JsonApiUseIriAsIdDeprecationTest.php => JsonApiUseIriAsIdTest.php} (81%) diff --git a/CHANGELOG.md b/CHANGELOG.md index d16b38ed4b7..8f042c52fa7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v5.0.0-alpha.4 + +### Breaking changes + +* JSON:API: `use_iri_as_id` now defaults to `false` instead of resolving to `true` with a deprecation, as announced in #8327. The `data.id` member carries the resource identifier and the IRI moves to `data.links.self`. Set `api_platform.jsonapi.use_iri_as_id` to `true` (Symfony) or `'jsonapi' => ['use_iri_as_id' => true]` in `config/api-platform.php` (Laravel) to keep the previous payload. + ## v5.0.0-alpha.3 ### Features diff --git a/src/Laravel/ApiPlatformProvider.php b/src/Laravel/ApiPlatformProvider.php index 7d43ace6e04..afd2e008738 100644 --- a/src/Laravel/ApiPlatformProvider.php +++ b/src/Laravel/ApiPlatformProvider.php @@ -1053,7 +1053,7 @@ public function register(): void $config = $app['config']; $defaultContext = $config->get('api-platform.serializer', []); $defaultContext[JsonApiItemNormalizer::ALLOW_CLIENT_GENERATED_ID] = (bool) $config->get('api-platform.jsonapi.allow_client_generated_id', false); - $useIriAsId = (bool) $config->get('api-platform.jsonapi.use_iri_as_id', true); + $useIriAsId = (bool) $config->get('api-platform.jsonapi.use_iri_as_id', false); return new JsonApiItemNormalizer( $app->make(PropertyNameCollectionFactoryInterface::class), diff --git a/src/Laravel/Tests/JsonApiTest.php b/src/Laravel/Tests/JsonApiTest.php index 1c987a4dd6c..91fc7d1534b 100644 --- a/src/Laravel/Tests/JsonApiTest.php +++ b/src/Laravel/Tests/JsonApiTest.php @@ -45,6 +45,8 @@ protected function defineEnvironment($app): void $config->set('api-platform.docs_formats', ['jsonapi' => ['application/vnd.api+json']]); $config->set('api-platform.resources', [app_path('Models'), app_path('ApiResource')]); $config->set('api-platform.pagination.items_per_page_parameter_name', 'limit'); + // This suite asserts IRIs in "data.id", which is no longer the default since 5.0. + $config->set('api-platform.jsonapi.use_iri_as_id', true); $config->set('api-platform.defaults', [ 'route_prefix' => '/api', 'parameters' => [ diff --git a/src/Laravel/Tests/JsonProblemTest.php b/src/Laravel/Tests/JsonProblemTest.php index 43027506711..251c301232d 100644 --- a/src/Laravel/Tests/JsonProblemTest.php +++ b/src/Laravel/Tests/JsonProblemTest.php @@ -111,7 +111,7 @@ public static function formatsProvider(): array [ 'errors' => [ [ - 'id' => '/api/errors/401', + 'id' => '401', 'detail' => 'Unauthorized', 'type' => 'about:blank', 'title' => 'Error 401', diff --git a/src/Laravel/config/api-platform.php b/src/Laravel/config/api-platform.php index c89c853be27..52ae847eb32 100644 --- a/src/Laravel/config/api-platform.php +++ b/src/Laravel/config/api-platform.php @@ -84,10 +84,10 @@ ], 'jsonapi' => [ - // When false, the JSON:API `data.id` uses the resource scalar identifier - // and a `data.links.self` IRI is added. When true (default), `data.id` + // When false (default), the JSON:API `data.id` uses the resource scalar + // identifier and a `data.links.self` IRI is added. When true, `data.id` // is the resource IRI. - 'use_iri_as_id' => true, + 'use_iri_as_id' => false, // Allow client-generated IDs on JSON:API POST per // https://jsonapi.org/format/#crud-creating-client-ids. Off by default diff --git a/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php b/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php index ff3757f933f..3a75bcba35d 100644 --- a/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php +++ b/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php @@ -716,10 +716,6 @@ private function registerJsonApiConfiguration(ContainerBuilder $container, array $loader->load('state/jsonapi.php'); $useIriAsId = $config['jsonapi']['use_iri_as_id']; - if (null === $useIriAsId) { - trigger_deprecation('api-platform/core', '4.4', 'Not setting "api_platform.jsonapi.use_iri_as_id" explicitly is deprecated. Its default value will change from "true" to "false" in API Platform 5.0. Set it to "true" to keep the current behavior or to "false" to use entity identifiers as the "id" field, and silence this deprecation.'); - $useIriAsId = true; - } $itemNormalizer = $container->getDefinition('api_platform.jsonapi.normalizer.item'); $itemNormalizer->replaceArgument(7, [JsonApiItemNormalizer::ALLOW_CLIENT_GENERATED_ID => $config['jsonapi']['allow_client_generated_id'] ?? false]); diff --git a/src/Symfony/Bundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/DependencyInjection/Configuration.php index fb070df0506..299e0b88aef 100644 --- a/src/Symfony/Bundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/DependencyInjection/Configuration.php @@ -101,8 +101,8 @@ public function getConfigTreeBuilder(): TreeBuilder ->addDefaultsIfNotSet() ->children() ->booleanNode('use_iri_as_id') - ->defaultNull() - ->info('Set to false to use entity identifiers instead of IRIs as the "id" field in JSON:API responses. Defaults to true; this default will change to false in API Platform 5.0.') + ->defaultFalse() + ->info('Set to true to use IRIs instead of entity identifiers as the "id" field in JSON:API responses. Defaults to false, which uses the entity identifier and exposes the IRI as "links.self".') ->end() ->booleanNode('allow_client_generated_id') ->defaultFalse() diff --git a/src/Symfony/Tests/Bundle/DependencyInjection/JsonApiUseIriAsIdDeprecationTest.php b/src/Symfony/Tests/Bundle/DependencyInjection/JsonApiUseIriAsIdTest.php similarity index 81% rename from src/Symfony/Tests/Bundle/DependencyInjection/JsonApiUseIriAsIdDeprecationTest.php rename to src/Symfony/Tests/Bundle/DependencyInjection/JsonApiUseIriAsIdTest.php index 83f34ce3c49..6b9c473ca4d 100644 --- a/src/Symfony/Tests/Bundle/DependencyInjection/JsonApiUseIriAsIdDeprecationTest.php +++ b/src/Symfony/Tests/Bundle/DependencyInjection/JsonApiUseIriAsIdTest.php @@ -20,8 +20,6 @@ use ApiPlatform\Tests\Fixtures\TestBundle\TestBundle; use Doctrine\Bundle\DoctrineBundle\DoctrineBundle; use Doctrine\ORM\OptimisticLockException; -use PHPUnit\Framework\Attributes\Group; -use PHPUnit\Framework\Attributes\IgnoreDeprecations; use PHPUnit\Framework\TestCase; use Symfony\Bundle\SecurityBundle\SecurityBundle; use Symfony\Bundle\TwigBundle\TwigBundle; @@ -29,7 +27,7 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\HttpFoundation\Response; -final class JsonApiUseIriAsIdDeprecationTest extends TestCase +final class JsonApiUseIriAsIdTest extends TestCase { private ContainerBuilder $container; @@ -56,19 +54,19 @@ protected function setUp(): void $this->container = new ContainerBuilder($containerParameterBag); } - #[Group('legacy')] - #[IgnoreDeprecations] - public function testNotSettingUseIriAsIdIsDeprecatedAndResolvesToTrue(): void + /** + * Since 5.0 the option defaults to "false": the "id" field carries the entity + * identifier and the IRI moves to "links.self". + */ + public function testNotSettingUseIriAsIdResolvesToFalse(): void { - $this->expectUserDeprecationMessage('Since api-platform/core 4.4: Not setting "api_platform.jsonapi.use_iri_as_id" explicitly is deprecated. Its default value will change from "true" to "false" in API Platform 5.0. Set it to "true" to keep the current behavior or to "false" to use entity identifiers as the "id" field, and silence this deprecation.'); - (new ApiPlatformExtension())->load($this->buildConfig(), $this->container); - $this->assertTrue($this->container->getDefinition('api_platform.jsonapi.normalizer.item')->getArgument(13)); - $this->assertTrue($this->container->getDefinition('api_platform.jsonapi.denormalizer.item')->getArgument(12)); + $this->assertFalse($this->container->getDefinition('api_platform.jsonapi.normalizer.item')->getArgument(13)); + $this->assertFalse($this->container->getDefinition('api_platform.jsonapi.denormalizer.item')->getArgument(12)); } - public function testSettingUseIriAsIdToFalseDoesNotDeprecateAndResolvesToFalse(): void + public function testSettingUseIriAsIdToFalseResolvesToFalse(): void { (new ApiPlatformExtension())->load($this->buildConfig(['use_iri_as_id' => false]), $this->container); @@ -76,7 +74,7 @@ public function testSettingUseIriAsIdToFalseDoesNotDeprecateAndResolvesToFalse() $this->assertFalse($this->container->getDefinition('api_platform.jsonapi.denormalizer.item')->getArgument(12)); } - public function testSettingUseIriAsIdToTrueDoesNotDeprecateAndResolvesToTrue(): void + public function testSettingUseIriAsIdToTrueResolvesToTrue(): void { (new ApiPlatformExtension())->load($this->buildConfig(['use_iri_as_id' => true]), $this->container); diff --git a/tests/Fixtures/app/config/config_common.yml b/tests/Fixtures/app/config/config_common.yml index 9add790eab7..0d0e22eafa1 100644 --- a/tests/Fixtures/app/config/config_common.yml +++ b/tests/Fixtures/app/config/config_common.yml @@ -61,6 +61,8 @@ api_platform: html: ['text/html'] xml: ['application/xml', 'text/xml'] jsonapi: + # Not the default since 5.0: kept explicitly so the shared test environment + # keeps covering the IRI-as-id mode. The "jsonapi" environment covers the default. use_iri_as_id: true graphql: enabled: true diff --git a/tests/Functional/JsonApi/IriModeTest.php b/tests/Functional/JsonApi/IriModeTest.php index 429748ad16d..e3f29cc4714 100644 --- a/tests/Functional/JsonApi/IriModeTest.php +++ b/tests/Functional/JsonApi/IriModeTest.php @@ -31,9 +31,9 @@ public static function getResources(): array return [JsonApiDummy::class]; } - public function testGetSingleResourceDefaultIriMode(): void + public function testGetSingleResourceIriMode(): void { - // Default mode (use_iri_as_id: true) — id is the IRI, no links.self + // use_iri_as_id: true, set by the shared test environment — id is the IRI, no links.self self::createClient()->request('GET', '/jsonapi_dummies/10', [ 'headers' => ['accept' => 'application/vnd.api+json'], ]); diff --git a/tests/Symfony/Bundle/DependencyInjection/ConfigurationTest.php b/tests/Symfony/Bundle/DependencyInjection/ConfigurationTest.php index b1d0a51c448..24c952b015a 100644 --- a/tests/Symfony/Bundle/DependencyInjection/ConfigurationTest.php +++ b/tests/Symfony/Bundle/DependencyInjection/ConfigurationTest.php @@ -244,7 +244,7 @@ private function runDefaultConfigTests(array $doctrineIntegrationsToLoad = ['orm 'format' => 'jsonld', ], 'jsonapi' => [ - 'use_iri_as_id' => null, + 'use_iri_as_id' => false, 'allow_client_generated_id' => false, ], 'enable_scalar' => true,