<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Grégoire Abachin</title>
    <description>The latest articles on Forem by Grégoire Abachin (@greg-ab).</description>
    <link>https://forem.com/greg-ab</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1219991%2F8bfc0bb3-5df6-4af4-bbce-3abaed4ee730.png</url>
      <title>Forem: Grégoire Abachin</title>
      <link>https://forem.com/greg-ab</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/greg-ab"/>
    <language>en</language>
    <item>
      <title>How to migrate from Api Platform v2 to v3?</title>
      <dc:creator>Grégoire Abachin</dc:creator>
      <pubDate>Wed, 29 Nov 2023 14:00:00 +0000</pubDate>
      <link>https://forem.com/theodo/how-to-migrate-from-api-platform-v2-to-v3-2nec</link>
      <guid>https://forem.com/theodo/how-to-migrate-from-api-platform-v2-to-v3-2nec</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was co-authored with &lt;a class="mentioned-user" href="https://dev.to/sebastientouze"&gt;@sebastientouze&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The API Platform team recently announced that it would be dropping support for version 2.x to focus on v3. Although it has opened a &lt;a href="https://opencollective.com/api-platform/projects/27-lts" rel="noopener noreferrer"&gt;Crowdfunding to offer Long Term Support on version 2.7&lt;/a&gt;, with Symfony 6.4 being released it is a good idea to prepare to migrate to the latest LTS versions of both Symfony (6.4) and APIPlatform (3.x). &lt;/p&gt;

&lt;p&gt;This article aims to share feedback from the API platform upgrades we've carried out at Theodo, so that you can do so with complete peace of mind. This article is a complement to the update guide and focuses on evolutions to be made on most code bases. For a more in-depth look, you can find the complete list of BC breaks in the &lt;a href="https://api-platform.com/docs/changelog/" rel="noopener noreferrer"&gt;CHANGELOG&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migrate Api Platform to v2.7 and prepare for v3
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Ensure no regression after the upgrade
&lt;/h3&gt;

&lt;p&gt;Before updating Api Platform, you should make sure that your Api Platform routes are fully covered by tests. You can define integration tests with &lt;a href="https://phpunit.de/" rel="noopener noreferrer"&gt;PHPUnit&lt;/a&gt;, &lt;a href="https://docs.behat.org/en/latest/" rel="noopener noreferrer"&gt;Behat&lt;/a&gt; or &lt;a href="https://pestphp.com/docs/writing-tests" rel="noopener noreferrer"&gt;Pest&lt;/a&gt;, depending on the tool you’re most comfortable with.&lt;/p&gt;

&lt;p&gt;Here is an example of a PHPUnit test that checks that the &lt;code&gt;/api/books&lt;/code&gt; route returns a &lt;code&gt;200&lt;/code&gt; HTTP status code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Tests&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Symfony\Bundle\FrameworkBundle\Test\WebTestCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BookTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;WebTestCase&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;    
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testGetBooks&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'GET'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/api/books'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getResponse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getStatusCode&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="c1"&gt;// Add additional assertions here depending on your needs&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more information about testing Api Platform routes, see the &lt;a href="https://api-platform.com/docs/distribution/testing/" rel="noopener noreferrer"&gt;Testing&lt;/a&gt; section of the documentation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: All your routes should be covered by tests before updating Api Platform. If you don’t have tests yet, we strongly recommend that you write them before updating Api Platform.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A good way to be sure all your routes are covered is to use the &lt;code&gt;--coverage&lt;/code&gt; option for Pest, or &lt;code&gt;--coverage-clover&lt;/code&gt; (&lt;a href="https://docs.phpunit.de/en/10.4/textui.html#code-coverage" rel="noopener noreferrer"&gt;or any other format&lt;/a&gt;) for PHPUnit. Keep in mind that Api Platform routes are not directly defined in your code, but your custom filters, custom controllers and any other additional logic will be. &lt;/p&gt;

&lt;p&gt;To list all available routes, you can use the Symfony command &lt;code&gt;bin/console debug:router&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Follow Api Platform’s upgrade guide
&lt;/h3&gt;

&lt;p&gt;Api Platform v2.7 is a transition version between v2 and v3. It contains all the features of v3 which you can enable using a flag. All the features that will be removed in v3 are marked as deprecated. It is a good way to migrate your application to v3 progressively.&lt;/p&gt;

&lt;p&gt;Api Platform provides a &lt;a href="https://api-platform.com/docs/core/upgrade-guide/" rel="noopener noreferrer"&gt;migration guide&lt;/a&gt;. It contains a lot of useful information to migrate your application and lists most of the BC breaks and deprecations.&lt;/p&gt;

&lt;p&gt;The key steps are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update Api Platform to v2.7 in your &lt;code&gt;composer.json&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Run the command &lt;a href="https://api-platform.com/docs/core/upgrade-guide/#the-upgrade-command" rel="noopener noreferrer"&gt;api:upgrade-resource&lt;/a&gt; to let Api Platform handle most of the BC breaks for you.&lt;/li&gt;
&lt;li&gt;Handle the remaining deprecations listed in the guide and fix the BC breaks&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: You should not change the value of the &lt;code&gt;metadata_backward_compatibility_layer&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt; yet, as it may break your application. You can change it to false once you have fixed all the BC breaks described below.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Ensure all resources are correctly migrated
&lt;/h3&gt;

&lt;p&gt;After running the upgrade command, you should check that all your resources are correctly migrated.&lt;/p&gt;

&lt;h4&gt;
  
  
  Check that all routes are still available
&lt;/h4&gt;

&lt;p&gt;You can do so by running the command &lt;a href="https://api-platform.com/docs/v2.7/core/openapi/#using-the-openapi-command" rel="noopener noreferrer"&gt;api:openapi:export&lt;/a&gt; (with the option &lt;code&gt;--output=swagger_docs.json&lt;/code&gt;) and comparing the generated output file with the previous version you had.&lt;/p&gt;

&lt;h4&gt;
  
  
  Check that all routes are declared in the right order
&lt;/h4&gt;

&lt;p&gt;After the upgrade, you should check that all your routes are declared in the right order. With the new update, the order of the routes becomes important.&lt;/p&gt;

&lt;p&gt;For example, if you had multiple routes defined for the same operation, with the following order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * @ApiResource(
 *     collectionOperations={
 *         "get",
 *         "export"": {
 *             "method": "GET",
 *             "path": "/invoices/generate-recap",
 *             "pagination_enabled": false,
 *             "controller": GenerateRecapInvoiceController::class,
 *         },
 *     },
 * )
 */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the upgrade command, the &lt;code&gt;export&lt;/code&gt; route will become a &lt;code&gt;GetCollection&lt;/code&gt; operation just like the &lt;code&gt;get&lt;/code&gt; route. The &lt;code&gt;export&lt;/code&gt; route will be declared after the &lt;code&gt;get&lt;/code&gt; route and will therefore never be called:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;ApiResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;operations&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GetCollection&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GetCollection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;uriTemplate&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'/invoices/generate-recap'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;paginationEnabled&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GenerateRecapInvoiceController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To fix this issue, you should declare the &lt;code&gt;export&lt;/code&gt; route, with the most specific route pattern first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;#[ApiResource(
    operations: [
&lt;span class="gd"&gt;-       new GetCollection(),
&lt;/span&gt;        new GetCollection(
            uriTemplate: '/invoices/generate-recap',
            paginationEnabled: false,
            controller: GenerateRecapInvoiceController::class 
       ),
&lt;span class="gi"&gt;+       new GetCollection(),
&lt;/span&gt;    ],
)]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That error can be hard to spot, especially if you have a lot of routes. This is why integration tests are important for each of your routes.&lt;/p&gt;

&lt;h4&gt;
  
  
  Migrate your custom Api Platform Event Subscribers
&lt;/h4&gt;

&lt;p&gt;If you had custom Api Platform Event Subscribers to implement some additional logic on your routes and relied on request attributes, you should update them to use the new behavior.&lt;/p&gt;

&lt;p&gt;Attributes &lt;code&gt;_api_item_operation_name&lt;/code&gt;, &lt;code&gt;_api_collection_operation_name&lt;/code&gt;, &lt;code&gt;_api_subresource_operation_name&lt;/code&gt; are deprecated and replaced by &lt;code&gt;_api_operation_name&lt;/code&gt; and &lt;code&gt;_api_operation&lt;/code&gt; and will become unavailable when you will switch the &lt;code&gt;metadata_backward_compatibility_layer&lt;/code&gt; flag to &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That logic is implemented in the &lt;code&gt;ApiPlatform\Util\AttributesExtractor.php&lt;/code&gt; class, which has been updated and that you can use to retrieve the &lt;code&gt;operation_name&lt;/code&gt; and the &lt;code&gt;operation&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you already used the &lt;code&gt;ApiPlatform\Core\Util\AttributesExtractor.php&lt;/code&gt; class, you should update it to use the new one and pay attention to the following changes (from the apiplatform-core github repository):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;// ApiPlatform\Util\AttributesExtractor.php (2.6 -&amp;gt; 2.7)
&lt;span class="gd"&gt;-        foreach (OperationType::TYPES as $operationType) {
-            $attribute = "_api_{$operationType}_operation_name";
-            if (isset($attributes[$attribute])) {
-                $result["{$operationType}_operation_name"] = $attributes[$attribute];
-                $hasRequestAttributeKey = true;
-                break;
&lt;/span&gt;&lt;span class="gi"&gt;+        if (isset($attributes['_api_operation_name'])) {
+            $hasRequestAttributeKey = true;
+            $result['operation_name'] = $attributes['_api_operation_name'];
+        }
+        if (isset($attributes['_api_operation'])) {
+            $result['operation'] = $attributes['_api_operation'];
+        }
+
+        // TODO: remove in 3.0
+        if (!isset($result['operation']) || ($result['operation']-&amp;gt;getExtraProperties()['is_legacy_resource_metadata'] ?? false) || ($result['operation']-&amp;gt;getExtraProperties()['is_legacy_subresource'] ?? false)) {
+            foreach (OperationType::TYPES as $operationType) {
+                $attribute = "_api_{$operationType}_operation_name";
+                if (isset($attributes[$attribute])) {
+                    $result["{$operationType}_operation_name"] = $attributes[$attribute];
+                    $hasRequestAttributeKey = true;
+                    break;
+                }
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Route names
&lt;/h4&gt;

&lt;p&gt;If you relied on route names, note that they have also been changed as part of this update. A route declared as &lt;code&gt;api_books_get_collection&lt;/code&gt; in 2.6 is now declared as &lt;code&gt;_api_/books.{_format}_get_collection&lt;/code&gt; in 2.7.&lt;/p&gt;

&lt;h4&gt;
  
  
  Migrate your custom route Controllers
&lt;/h4&gt;

&lt;p&gt;If you had custom route Controllers and used a path parameter to retrieve the resource, you should update them to use the new behavior. The path parameter must now be named &lt;code&gt;id&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;#[ApiResource(
    operations: [
        new Post(
&lt;span class="gd"&gt;-            uriTemplate: '/authors/{selectedAuthor}/book',
&lt;/span&gt;&lt;span class="gi"&gt;+            uriTemplate: '/authors/{id}/book',
&lt;/span&gt;            controller: CreateBookLinkedToAuthorController::class,
        ),
    ],
)]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Migrate from DataProviders and DataPersisters to Providers and Processors
&lt;/h4&gt;

&lt;p&gt;If you had custom DataProviders and DataPersisters, you should update them to use the new Providers and Processors. The same applies to custom DataTransformers, which can be replaced by a combination of a Processor and a Provider.&lt;/p&gt;

&lt;p&gt;Refer to the &lt;a href="https://api-platform.com/docs/v2.7/core/state-providers/" rel="noopener noreferrer"&gt;state Providers&lt;/a&gt; and &lt;a href="https://api-platform.com/docs/v2.7/core/state-processors/" rel="noopener noreferrer"&gt;state Processors&lt;/a&gt; sections of the documentation for more information.&lt;/p&gt;

&lt;p&gt;You can find an &lt;a href="https://blog.theodo.com/2023/04/filter-subresources-with-api-platform/" rel="noopener noreferrer"&gt;example of a DataProvider implementation on our blog&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Change the value of the &lt;code&gt;metadata_backward_compatibility_layer&lt;/code&gt; flag
&lt;/h4&gt;

&lt;p&gt;You’re all set to migrate to Api Platform v3! &lt;/p&gt;

&lt;p&gt;The last step is to update the &lt;code&gt;metadata_backward_compatibility_layer&lt;/code&gt; flag to &lt;code&gt;false&lt;/code&gt; in your &lt;code&gt;api_platform.yaml&lt;/code&gt; file and ensure that all your tests are still passing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migrate to Api Platform v3
&lt;/h2&gt;

&lt;p&gt;Now, you are ready to migrate to Api Platform v3!&lt;/p&gt;

&lt;p&gt;We recommend you migrate to the latest stable version of Api Platform v3. You can find the latest stable version and the latest changes in the &lt;a href="https://api-platform.com/docs/changelog/" rel="noopener noreferrer"&gt;CHANGELOG&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Api Platform v3 requires the latest version of PHP and Symfony, you will need to update both before switching to the latest API Platform version.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Api Platform version&lt;/th&gt;
&lt;th&gt;PHP Version&lt;/th&gt;
&lt;th&gt;Symfony Version&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2.7&lt;/td&gt;
&lt;td&gt;≥ 7.1&lt;/td&gt;
&lt;td&gt;^4.4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.0, 3.1, 3.2&lt;/td&gt;
&lt;td&gt;≥ 8.1&lt;/td&gt;
&lt;td&gt;^6.1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;While only version 8.1 for PHP and 6.1 for Symfony are required, we recommend updating to the latest version that offers Long Term Support. You can find information on actively supported versions here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.php.net/supported-versions.php" rel="noopener noreferrer"&gt;PHP Versions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://symfony.com/releases" rel="noopener noreferrer"&gt;Symfony Versions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For instance, there are &lt;a href="https://github.com/api-platform/core/issues/5285" rel="noopener noreferrer"&gt;cache problems on Api Platform v3.0&lt;/a&gt;, so you should consider upgrading directly to the latest minor version available.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update the bundle declaration
&lt;/h3&gt;

&lt;p&gt;Update the Api Platform bundle declaration in your &lt;code&gt;config/bundles.php&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;return [
&lt;/span&gt;    // ...
&lt;span class="gd"&gt;-   ApiPlatform\Core\Bridge\Symfony\Bundle\ApiPlatformBundle::class =&amp;gt; ['all' =&amp;gt; true],
&lt;/span&gt;&lt;span class="gi"&gt;+   ApiPlatform\Symfony\Bundle\ApiPlatformBundle::class =&amp;gt; ['all' =&amp;gt; true],
&lt;/span&gt;]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bundle has been moved from &lt;code&gt;ApiPlatform\Core\Bridge\Symfony\Bundle\ApiPlatformBundle&lt;/code&gt; to &lt;code&gt;ApiPlatform\Symfony\Bundle\ApiPlatformBundle&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check all imports still work
&lt;/h3&gt;

&lt;p&gt;Now that you have migrated to Api Platform v3, you should check that all your imports still work. Here are some imports that have changed and are not handled by the upgrade command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;- use ApiPlatform\Core\Action\NotFoundAction;
&lt;/span&gt;&lt;span class="gi"&gt;+ use ApiPlatform\Action\NotFoundAction;
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gd"&gt;- use ApiPlatform\Core\Annotation\ApiProperty;
&lt;/span&gt;&lt;span class="gi"&gt;+ use ApiPlatform\Metadata\ApiProperty;
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gd"&gt;- use ApiPlatform\Core\EventListener\EventPriorities;
&lt;/span&gt;&lt;span class="gi"&gt;+ use ApiPlatform\Symfony\EventListener\EventPriorities;
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gd"&gt;- use ApiPlatform\Core\JsonApi\Serializer\CollectionNormalizer;
&lt;/span&gt;&lt;span class="gi"&gt;+ use ApiPlatform\JsonApi\Serializer\CollectionNormalizer;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update types on Api Platform classes you extend
&lt;/h3&gt;

&lt;p&gt;Some return types and parameter types have changed on Api Platform classes and / or on Symfony classes. You should update them in your classes that extend them.&lt;/p&gt;

&lt;p&gt;For instance, in your custom filters, you should update the type of the &lt;code&gt;$value&lt;/code&gt; parameter in the &lt;code&gt;filterProperty&lt;/code&gt; method to &lt;code&gt;mixed&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;    /**
     * @param mixed[] $context
     */
    protected function filterProperty(
        string $property,
&lt;span class="gd"&gt;-        $value,
&lt;/span&gt;&lt;span class="gi"&gt;+        mixed $value,
&lt;/span&gt;        QueryBuilder $queryBuilder,
        QueryNameGeneratorInterface $queryNameGenerator,
        string $resourceClass,
&lt;span class="gd"&gt;-        string $operationName = null,
&lt;/span&gt;&lt;span class="gi"&gt;+        Operation $operation = null,
&lt;/span&gt;        array $context = []
    ): void {
        / ...
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update your frontend types
&lt;/h3&gt;

&lt;p&gt;One of the main changes brought about by Api Platform v3 is that null is no longer one of the default return types. This may have consequences for your front-end, especially if you use TypeScript. You may need to update your types to take null values into account.&lt;/p&gt;

&lt;p&gt;According to &lt;a href="https://api-platform.com/docs/core/upgrade-guide/" rel="noopener noreferrer"&gt;Api Platform’s upgrade guide&lt;/a&gt;, this follows a JSON Merge Patch RFC:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In 3.0, in conformance with the JSON Merge Patch RFC, the default value of the &lt;code&gt;skip_null_values&lt;/code&gt; property is true which means that from now on null values are omitted during serialization. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For instance, on a UserMetadata object, frontend types should be updated to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;export type UserMetadata = {
&lt;/span&gt;  id: string;
  fullName: string;
&lt;span class="gd"&gt;-  firstName: string | null;
-  lastName: string | null;
-  phoneNumber: string | null;
&lt;/span&gt;&lt;span class="gi"&gt;+  firstName?: string;
+  lastName?: string;
+  phoneNumber?: string;
&lt;/span&gt;};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary of a successful migration from API Platform v2 to v3
&lt;/h2&gt;

&lt;p&gt;Transitioning from API Platform v2 to v3 is a progressive process, which involves first upgrading to the transitional v2.7, ensuring all relevant routes are covered by tests, and then gradually migrating to v3. &lt;/p&gt;

&lt;p&gt;This process requires careful attention to changes in route names and imports, behavior of custom controllers, changes in Providers and Processors, bundle declarations, among other breaking changes. &lt;/p&gt;

&lt;p&gt;Once these steps are completed, it is also crucial to verify that front-end types are updated to account for the change in default return types. &lt;/p&gt;

&lt;p&gt;After completing this process, your API should be fully updated and ready to benefit from the features and improvements in API Platform v3.&lt;/p&gt;

&lt;p&gt;This migration is also a good opportunity to check that all your routes are secure. To do so, we recommend reading our &lt;a href="https://blog.theodo.com/2023/10/ensure-that-symfony-routes-have-access-control/" rel="noopener noreferrer"&gt;article on Access Control&lt;/a&gt;, which is compatible with v3!&lt;/p&gt;

</description>
      <category>php</category>
      <category>api</category>
      <category>symfony</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
