If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
We already added a denyAccessUnlessGranted()
line to ProgrammerController::newAction()
.
That means this endpoint is broken: we don't have an API authentication system hooked
up yet.
Open up ProgrammerControllerTest()
and find testPOST()
: the test for this endpoint:
... lines 1 - 6 | |
class ProgrammerControllerTest extends ApiTestCase | |
{ | |
... lines 9 - 15 | |
public function testPOST() | |
{ | |
... lines 18 - 34 | |
} | |
... lines 36 - 254 | |
} |
Rename this to testPOSTProgrammerWorks()
- this will make its name unique enough
that we can run it alone:
... lines 1 - 6 | |
class ProgrammerControllerTest extends ApiTestCase | |
{ | |
... lines 9 - 15 | |
public function testPOSTProgrammerWorks() | |
{ | |
... lines 18 - 40 | |
} | |
... lines 42 - 260 | |
} |
Copy that name and run it:
./vendor/bin/phpunit --filter testPOSTProgrammerWorks
Instead of the 201, we get a 200 status code after being redirected to /login
.
I know we don't have our security system hooked up yet, but pretend that it is
hooked up and working nicely. How can we update the test to send a token?
Well, first, we'll need to create a valid token. Do that the same way we just did in
the controller: $token = $this->getService()
- which is just a shortcut we made
to fetch a service from the container - and grab the lexik_jwt_authentication.encoder
service. Finally, call encode()
and pass it ['username' => 'weaverryan']
:
... lines 1 - 6 | |
class ProgrammerControllerTest extends ApiTestCase | |
{ | |
... lines 9 - 15 | |
public function testPOSTProgrammerWorks() | |
{ | |
$data = array( | |
'nickname' => 'ObjectOrienter', | |
'avatarNumber' => 5, | |
'tagLine' => 'a test dev!' | |
); | |
$token = $this->getService('lexik_jwt_authentication.encoder') | |
->encode(['username' => 'weaverryan']); | |
... lines 26 - 40 | |
} | |
... lines 42 - 260 | |
} |
And we have a token! Now, how do we send it to the server? Well, it's our API, so we
can do whatever the heck we want! We can set it as a query string or attach it on
a header. The most common way is to set it on a header called Authorization
.
Add a headers
key to the Guzzle call with one header called Authorization
. Set
its value to the word Bearer
, a space, and then the $token.
:
... lines 1 - 6 | |
class ProgrammerControllerTest extends ApiTestCase | |
{ | |
... lines 9 - 15 | |
public function testPOSTProgrammerWorks() | |
{ | |
... lines 18 - 26 | |
// 1) Create a programmer resource | |
$response = $this->client->post('/api/programmers', [ | |
'body' => json_encode($data), | |
'headers' => [ | |
'Authorization' => 'Bearer '.$token | |
] | |
]); | |
... lines 34 - 40 | |
} | |
... lines 42 - 260 | |
} |
Weird as it might look, this is a really standard way to send a token to an API. If we re-run the test now, it of course still fails. But we're finally ready to create an authentication system that looks for this token and authenticates our user.
// composer.json
{
"require": {
"php": ">=5.5.9",
"symfony/symfony": "3.0.*", // v3.0.3
"doctrine/orm": "^2.5", // v2.5.4
"doctrine/doctrine-bundle": "^1.6", // 1.6.2
"doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
"symfony/swiftmailer-bundle": "^2.3", // v2.3.11
"symfony/monolog-bundle": "^2.8", // v2.10.0
"sensio/distribution-bundle": "^5.0", // v5.0.4
"sensio/framework-extra-bundle": "^3.0.2", // v3.0.14
"incenteev/composer-parameter-handler": "~2.0", // v2.1.2
"jms/serializer-bundle": "^1.1.0", // 1.1.0
"white-october/pagerfanta-bundle": "^1.0", // v1.0.5
"lexik/jwt-authentication-bundle": "^1.4" // v1.4.3
},
"require-dev": {
"sensio/generator-bundle": "^3.0", // v3.0.6
"symfony/phpunit-bridge": "^3.0", // v3.0.3
"behat/behat": "~3.1@dev", // dev-master
"behat/mink-extension": "~2.2.0", // v2.2
"behat/mink-goutte-driver": "~1.2.0", // v1.2.1
"behat/mink-selenium2-driver": "~1.3.0", // v1.3.1
"phpunit/phpunit": "~4.6.0", // 4.6.10
"doctrine/doctrine-fixtures-bundle": "^2.3" // 2.3.0
}
}