DELETE to Remove Data [API Platform]
We can now GET
, POST
, and PUT
when working with our API Platform Album resources. It would be super nice to round off with a DELETE
implementation. So let's do that, shall we?
As we've covered in all of the previous videos in this API Platform tutorial, mostly the hard work has already been done for us. If we weren't customising our Operations slightly, there's very little we'd need to do after simply defining our entity / data model.
Let's start by looking at our existing Behat test:
Feature: Provide a consistent standard JSON API endpoint
In order to build interchangeable front ends
As a JSON API developer
I need to allow Create, Read, Update, and Delete functionality
Background:
Given there are Albums with the following details:
| title | track_count | release_date |
| some fake album name | 12 | 2020-01-08T00:00:00+00:00 |
| another great album | 9 | 2019-01-07T23:22:21+00:00 |
| now that's what I call Album vol 2 | 23 | 2018-02-06T11:10:09+00:00 |
And the "Content-Type" request header is "application/json"
Scenario: Can delete an Album
Given I request "/album/3" using HTTP GET
Then the response code is 200
When I request "/album/3" using HTTP DELETE
Then the response code is 204
When I request "/album/3" using HTTP GET
Then the response code is 404
The DELETE
test is a little unusual.
Because we have no direct access to the database we instead rely on consuming the API directly to ensure:
- The resource exists
- We can delete the resource
- The resource no longer exists
If you have been following along with the previous videos you will know also that as we haven't explicitly defined our DELETE
item operation, yet we have defined some custom item operations, that the DELETE
route will not exist.
We need to add in another annotation. It's very easy - pretty much just copy / paste what we used for GET
and PUT
:
<?php
// api/src/Entity/Album.php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiProperty;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ApiResource(
* collectionOperations = {
* "get"={
* "method"="GET",
* "path"="/album.{_format}",
* },
* "post"={
* "method"="POST",
* "path"="/album.{_format}",
* },
* },
* itemOperations={
* "get"={
* "method"="GET",
* "path"="/album/{id}.{_format}",
* },
+* "delete"={
+* "method"="DELETE",
+* "path"="/album/{id}.{_format}",
+* },
* "put"={
* "method"="PUT",
* "path"="/album/{id}.{_format}",
* },
* }
* )
* @ORM\Entity()
* @ApiResource(iri="http://schema.org/MusicAlbum")
*/
class Album
{
Which gives us the expected route:
docker-compose exec php php bin/console debug:router
---------------------------- -------- -------- ------ ---------------------------------
Name Method Scheme Host Path
---------------------------- -------- -------- ------ ---------------------------------
api_albums_get_collection GET ANY ANY /album.{_format}
api_albums_post_collection POST ANY ANY /album.{_format}
api_albums_get_item GET ANY ANY /album/{id}.{_format}
api_albums_delete_item DELETE ANY ANY /album/{id}.{_format}
api_albums_put_item PUT ANY ANY /album/{id}.{_format}
---------------------------- -------- -------- ------ ---------------------------------
And running the test:
vendor/bin/behat features/album.feature --tags=t
Feature: Provide a consistent standard JSON API endpoint
In order to build interchangeable front ends
As a JSON API developer
I need to allow Create, Read, Update, and Delete functionality
Background: # features/album.feature:7
Given there are Albums with the following details: # FeatureContext::thereAreAlbumsWithTheFollowingDetails()
| title | track_count | release_date |
| some fake album name | 12 | 2020-01-08T00:00:00+00:00 |
| another great album | 9 | 2019-01-07T23:22:21+00:00 |
| now that's what I call Album vol 2 | 23 | 2018-02-06T11:10:09+00:00 |
And the "Content-Type" request header is "application/json" # Imbo\BehatApiExtension\Context\ApiContext::setRequestHeader()
@t
Scenario: Can delete an Album # features/album.feature:43
Given I request "/album/3" using HTTP GET # Imbo\BehatApiExtension\Context\ApiContext::requestPath()
Then the response code is 200 # Imbo\BehatApiExtension\Context\ApiContext::assertResponseCodeIs()
When I request "/album/3" using HTTP DELETE # Imbo\BehatApiExtension\Context\ApiContext::requestPath()
Then the response code is 204 # Imbo\BehatApiExtension\Context\ApiContext::assertResponseCodeIs()
When I request "/album/3" using HTTP GET # Imbo\BehatApiExtension\Context\ApiContext::requestPath()
Then the response code is 404 # Imbo\BehatApiExtension\Context\ApiContext::assertResponseCodeIs()
1 scenario (1 passed)
8 steps (8 passed)
0m0.19s (9.82Mb)
Wow, the easiest one yet.
All we have left to do are the error checks.