Chapters
28 Chapters
|
2:51:42
|
Login to bookmark this video
-
Course Code
Subscribe to download the code!
Subscribe to download the code!
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Subtitles
Subscribe to download the subtitles!
Subscribe to download the subtitles!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Subscribe to jump to this part in the video!
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": ">=8.2",
"ext-ctype": "*",
"ext-iconv": "*",
"api-platform/core": "^3.0", // v3.0.8
"doctrine/annotations": "^1.0", // 1.14.2
"doctrine/doctrine-bundle": "^2.8", // 2.8.0
"doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.2
"doctrine/orm": "^2.14", // 2.14.0
"nelmio/cors-bundle": "^2.2", // 2.2.0
"nesbot/carbon": "^2.64", // 2.64.1
"phpdocumentor/reflection-docblock": "^5.3", // 5.3.0
"phpstan/phpdoc-parser": "^1.15", // 1.15.3
"symfony/asset": "6.2.*", // v6.2.0
"symfony/console": "6.2.*", // v6.2.3
"symfony/dotenv": "6.2.*", // v6.2.0
"symfony/expression-language": "6.2.*", // v6.2.2
"symfony/flex": "^2", // v2.2.4
"symfony/framework-bundle": "6.2.*", // v6.2.3
"symfony/property-access": "6.2.*", // v6.2.3
"symfony/property-info": "6.2.*", // v6.2.3
"symfony/runtime": "6.2.*", // v6.2.0
"symfony/security-bundle": "6.2.*", // v6.2.3
"symfony/serializer": "6.2.*", // v6.2.3
"symfony/twig-bundle": "6.2.*", // v6.2.3
"symfony/ux-react": "^2.6", // v2.6.1
"symfony/validator": "6.2.*", // v6.2.3
"symfony/webpack-encore-bundle": "^1.16", // v1.16.0
"symfony/yaml": "6.2.*" // v6.2.2
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.2
"symfony/debug-bundle": "6.2.*", // v6.2.1
"symfony/maker-bundle": "^1.48", // v1.48.0
"symfony/monolog-bundle": "^3.0", // v3.8.0
"symfony/stopwatch": "6.2.*", // v6.2.0
"symfony/web-profiler-bundle": "6.2.*", // v6.2.4
"zenstruck/foundry": "^1.26" // v1.26.0
}
}
6 Comments
hi, regarding coolFactor, is there any way we can validate that the type must be numeric so the response will have status 422 with the error message instead of 400?
I tried the Type validation with numeric type but it doesn't work
Yo @Huy!
I think I understand :). In this case,
coolFactoris private property, so we're setting it via thesetCoolFactor()method. Because it has aninttype-hint -setCoolFactor(int $coolFactor)- if the user sendsapplefor this, it will fail during denormalization (i.e. it will fail to even SET the value). This gives us the 400 error. It never even GETS to the validation step.If you want to, instead, enforce this via validation, you need to allow the
coolFactorproperty to be set to a string... which you CAN do, but it's kind of a bummer to allow such a weird value to even get set into your entity (even if you will validate it). So, you would need to:A) Remove the
?intproperty type from thecoolFactorpropertyB) Remove the
inttype from thesetCoolFactor()methodThat will allow the serializer to set the value... and THEN validation will happen. Let me know if this helps!
Cheers!
Hi @weaverryan, thank you, it works but when I pass the correct coolFactor in the request body, it returns 400 error like below
The request:
The response:
Then I try to validate the $isPublished with the annotation #[Assert\Type('bool')] to make sure the isPublished must be boolean type (not number, string...). then I send the request with $isPublished = 123, although I tried the approach you suggested above like removing the ?bool int property type and bool type from setIsPublished, the response status is still 400 instead of 422.
Sample request:
POST api/treasures
Response 400:
This is my DragonTreasure entity
Could you suggest any ways to resolve this issue?
Hey @Huy!
Hmm. I have a feeling this is being caused by Doctrine. So when deserialization happens, it uses Symfony's property-info component to get the "type" of a property - e.g.
coolFactorin this case. To get the type, it looks for a true PHP type on the property, a type on the argument insetCoolFactor()and it even looks at your PHPDoc - e.g. for an@varabove the property. If It finds a type & the type send by the user doesn't match, it'll throw that 400 error.However, you have NONE of that. But I still think that SOMETHING is "guessing" the type of your field. The property-info component also gets metadata from Doctrine. And, because you don't have a
typein your column, this is a string field. And so, this might be telling the property info system that this is astringfield. Still, it's a bit annoying, since if you send the integer40, PHP can very easily cast that to the string'40'.Anyway, the only way that I know of around this problem - which might actually be perfect for you - is to set
ObjectNormalizer::DISABLE_TYPE_ENFORCEMENT => falsein your context. So you could add adenormalizationContextoption to your#[ApiResource]and set that there. Just be aware that the serializer will now ALWAYS set the value onto your properties, even if it's something crazy (e.g. the user could, I think, even send an array to thecoolFactorproperty). If your code explodes when that is set (before validation) that would trigger a 500 error.Anyway, with this option, you could actually, I think, re-add your property types, etc.
Cheers!
So, I'm a bit stumped as to WHY the serializer still thinks that
coolFactorHi @weaverryan
I followed your suggestion but it still didn't work. When I pass the coolFactor as an integer, the response status still is 400.
Moreover, I also can not find the ObjectNormalizer class, it seems the class AbstractObjectNormalizer instead
The DragonTreasure entity:
The sample request payload:
PATCH api/treasures/:id
Hey @Huy!
Hmm. First, yea,
AbstractObjectNormalizeris correct -ObjectNormalizershould work too (it's a sub-class), but the constant is onAbstractObjectNormalizer- so that's better anyway.So you're still getting a response that looks like this?
I don't know if it's related, but I did misspeak in my previous message. You will still need to NOT have an argument type on
setCoolFactor()and you still need to NOT have a property type on the$coolFactorproperty. This is because we DO need to allow the property to be set with astringtype (for example) so that we can THEN run validation on that.Cheers!
"Houston: no signs of life"
Start the conversation!