If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeBusca tu terminal y borra manualmente el directorio de caché:
rm -rf var/cache/*
Lo hago para que, cuando ejecutemos todas nuestras pruebas
symfony php bin/phpunit
veamos una advertencia de desaprobación, que es fascinante. Dice
Desde API Platform 3.1: en API Platform 4,
PUT
siempre sustituirá los datos. EstableceextraProperties["standard_put"]
entrue
en cada operación para evitar romper el comportamiento de PUT. UtilizaPATCH
para el comportamiento antiguo.
Vale... ¿qué significa eso? Ahora mismo, significa que nada ha cambiado: nuestra operación PUT
se comporta como siempre lo ha hecho. Pero, en la API Platform 4, el comportamiento de PUT
cambiará radicalmente. Y, en algún momento entre ahora y entonces, tenemos que optar por ese nuevo comportamiento para que no se rompa de repente cuando actualicemos a la versión 4 en el futuro.
¿Qué cambia exactamente? Ve a los documentos de la API y actualízalos. Utiliza la ruta GET
collection endpoint... y pulsa "Ejecutar", para que podamos obtener un ID válido.
Genial: tenemos un tesoro con el ID 1.
Ahora mismo, si enviamos una petición a PUT
con este ID, podemos enviar sólo un campo para actualizar sólo esa cosa. Por ejemplo, podemos enviar description
para cambiar sólo eso.
Ah, pero antes de Ejecutar esto, necesitamos haber iniciado sesión. En mi otra pestaña, rellenaré el formulario de inicio de sesión. Perfecto. Ahora ejecuta la operación PUT
.
Sí: pasamos sólo el campo description
, y sólo actualiza el campo description
: todos los demás campos permanecen igual.
Vaya, resulta que no es así como se supone que funciona PUT
según la especificación HTTP. PUT
se supone que es un "reemplazo". Lo que quiero decir es que, si enviamos sólo un campo, se supone que la operación PUT
toma ese nuevo recurso -que es sólo el único campo- y sustituye al recurso existente. Es una forma complicada de decir que, al utilizar PUT, tienes que enviar todos los campos, incluso los que no cambian. De lo contrario, se establecerán en null
.
Si te parece una locura, estoy de acuerdo, pero hay razones técnicas válidas para que sea así. La cuestión es que: así es como se supone que funciona PUT
y en la API Platform 4, así es como funcionará PUT
.
Sinceramente, hace que PUT
sea menos útil. Así que te darás cuenta de que en adelante utilizaré casi exclusivamente PATCH
.
Nos guste o no, en algún momento entre ahora y la API Platform 4, tenemos que decirle a la API Platform que está bien que cambie el comportamiento de PUT
al "nuevo" modo. Hagámoslo ahora añadiendo algo de configuración extra a cada atributo ApiResource
de nuestra aplicación.
Abre src/Entity/DragonTreasure.php
... y añade una nueva opción llamada extraProperties
ajustada a una matriz con standard_put
ajustada a true
:
... lines 1 - 27 | |
( | |
... lines 29 - 64 | |
extraProperties: [ | |
'standard_put' => true, | |
], | |
) | |
... lines 69 - 89 | |
class DragonTreasure | |
{ | |
... lines 92 - 249 | |
} |
¡Ya está! Cópialo... porque vamos a necesitarlo aquí abajo en esteApiResource
... aunque no tenga una operación PUT
:
... lines 1 - 27 | |
( | |
... lines 29 - 64 | |
extraProperties: [ | |
'standard_put' => true, | |
], | |
) | |
( | |
... lines 70 - 81 | |
extraProperties: [ | |
'standard_put' => true, | |
], | |
) | |
... lines 86 - 89 | |
class DragonTreasure | |
{ | |
... lines 92 - 249 | |
} |
Luego, en User
, añádelo también a los dos puntos de ApiResource
:
... lines 1 - 25 | |
( | |
... lines 27 - 44 | |
extraProperties: [ | |
'standard_put' => true, | |
], | |
) | |
( | |
... lines 50 - 59 | |
extraProperties: [ | |
'standard_put' => true, | |
], | |
) | |
... lines 64 - 66 | |
class User implements UserInterface, PasswordAuthenticatedUserInterface | |
{ | |
... lines 69 - 276 | |
} |
Ahora, cuando ejecutemos nuestras pruebas, ¡la desaprobación habrá desaparecido! No estamos utilizando la operación PUT
en ninguna prueba, así que todo sigue pasando.
Para ver el nuevo comportamiento, prueba de nuevo la ruta PUT
: sigue enviando un solo campo. Esta vez... ¡fíjate! ¡Un error de validación 422! Todos los campos que no incluimos se establecieron como nulos... y eso provocó el fallo de validación.
Así que... esto hace que PUT
sea un poco menos útil... y nos apoyaremos mucho más en PATCH
. Si ya no quieres tener una operación PUT
, tiene mucho sentido. Una cosa única del nuevo comportamiento PUT
es que podrías utilizarlo para crear nuevos objetos... lo que podría ser útil en algunos casos extremos... o una absoluta pesadilla desde el punto de vista de la seguridad, ya que ahora tenemos que preocuparnos de que se editen o creen objetos mediante la misma operación PUT
. Por eso, a medida que avancemos, me verás eliminar la operación PUT
en algunos casos.
A continuación: vamos a complicar la seguridad asegurándonos de que un DragonTreasure
sólo pueda ser editado por su propietario.
"Houston: no signs of life"
Start the conversation!
// composer.json
{
"require": {
"php": ">=8.1",
"ext-ctype": "*",
"ext-iconv": "*",
"api-platform/core": "^3.0", // v3.1.2
"doctrine/annotations": "^2.0", // 2.0.1
"doctrine/doctrine-bundle": "^2.8", // 2.8.3
"doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.2
"doctrine/orm": "^2.14", // 2.14.1
"nelmio/cors-bundle": "^2.2", // 2.2.0
"nesbot/carbon": "^2.64", // 2.66.0
"phpdocumentor/reflection-docblock": "^5.3", // 5.3.0
"phpstan/phpdoc-parser": "^1.15", // 1.16.1
"symfony/asset": "6.2.*", // v6.2.5
"symfony/console": "6.2.*", // v6.2.5
"symfony/dotenv": "6.2.*", // v6.2.5
"symfony/expression-language": "6.2.*", // v6.2.5
"symfony/flex": "^2", // v2.2.4
"symfony/framework-bundle": "6.2.*", // v6.2.5
"symfony/property-access": "6.2.*", // v6.2.5
"symfony/property-info": "6.2.*", // v6.2.5
"symfony/runtime": "6.2.*", // v6.2.5
"symfony/security-bundle": "6.2.*", // v6.2.6
"symfony/serializer": "6.2.*", // v6.2.5
"symfony/twig-bundle": "6.2.*", // v6.2.5
"symfony/ux-react": "^2.6", // v2.7.1
"symfony/ux-vue": "^2.7", // v2.7.1
"symfony/validator": "6.2.*", // v6.2.5
"symfony/webpack-encore-bundle": "^1.16", // v1.16.1
"symfony/yaml": "6.2.*" // v6.2.5
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.2
"mtdowling/jmespath.php": "^2.6", // 2.6.1
"phpunit/phpunit": "^9.5", // 9.6.3
"symfony/browser-kit": "6.2.*", // v6.2.5
"symfony/css-selector": "6.2.*", // v6.2.5
"symfony/debug-bundle": "6.2.*", // v6.2.5
"symfony/maker-bundle": "^1.48", // v1.48.0
"symfony/monolog-bundle": "^3.0", // v3.8.0
"symfony/phpunit-bridge": "^6.2", // v6.2.5
"symfony/stopwatch": "6.2.*", // v6.2.5
"symfony/web-profiler-bundle": "6.2.*", // v6.2.5
"zenstruck/browser": "^1.2", // v1.2.0
"zenstruck/foundry": "^1.26" // v1.28.0
}
}