Lucky you! You found an early release chapter - it will be fully polished and published shortly!
Rest assured, the gnomes are hard at work
completing this video!
What about a test like this... but where we log in with an API key? Let's do that!
Create a new method: public function testPostToCreateTreasureWithApiKey()
.
This will start pretty much the same as before. I'll copy the top of the previous
test, remove the actingAs()
... and add a dump()
near the bottom. So, like before,
we're sending invalid data and expect a 422 status code.
Copy that method name, then spin over and run just this test:
symfony php bin/phpunit --filter=testPostToCreateTreasureWithApiKey
And... no surprise: we get a 401 status code because we're not authenticated.
Let's send an Authorization
header, but an invalid one to start. Pass a
headers
key set to an array with Authorization
and then word Bearer
and
then... foo
.
This should still fail:
symfony php bin/phpunit --filter=testPostToCreateTreasureWithApiKey
And... it does! But with a different error message: invalid_token
. Nice!
To pass a real token, we need to put a real token into the database. Do that
with $token = ApiTokenFactory::createOne()
.
Do we need to control any fields on this? We actually do. Open up DragonTreasure
.
If we scroll up, the Post
operation requires ROLE_TREASURE_CREATE
.
When we authenticate via the login form, thanks to role_hierarchy
, we always
have that. But when using an API key, to get that role, the token needs the
corresponding scope.
To make sure we have it, back in the test, set the scopes
property to
ApiToken::SCOPE_TREASURE_CREATE
.
Now pass this to the header: $token->getToken()
. Oh... and let me fix
scopes
: that should be an array.
I think we're ready! Run that test:
symfony php bin/phpunit --filter=testPostToCreateTreasureWithApiKey
And... got it! We see the beautiful 422 validation errors!
Let's test to make sure we don't have access if our token is missing this
scope. Copy the entire test method... then paste below. Call it
testPostToCreateTreasureDeniedWithoutScope()
.
This time, set scopes
to something else, like SCOPE_TREASURE_EDIT
. Below, we
now expect a 403 status code.
This time, let's run all the tests:
symfony php bin/phpunit
And... all green! A 422 then a 403. Go remove the dumps from both those spots.
By the way, if you use API tokens a lot in your tests, passing the Authorization
header can get annoying. Browser has a way where we can create a custom
Browser object with custom methods. For example, you could add an authWithToken()
method, pass an array of scopes, and then it would create that token and set
it into the header. This totally does not work right now, but check out Browser's
docs to learn how.
Next: in ApiPlatform 3.1, the behavior of the PUT
operation is changing. Let's
talk about how, and what we need to do in our code to prepare for it.
"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
}
}