API - GET a Collection of BlogPosts


In this video we are going to implement the collection GET - or cgetAction.

This is very similar to the getAction we implemented in the previous video, only this time we will return an array of BlogPosts, rather than an individual item.

To give you a more visual idea of what this means, consider this:

{
    "id": 36,
    "title": "a blog post title here",
    "body": "a blog post body here"
}

This would be a single BlogPost, represented as JSON, and returned from a call to:

http://api.symfony-3.dev/app_dev.php/posts/36

Now, with a collection, we would get multiple 'copies' of this same structure, only with different data, and wrapped in the JSON array syntax - []:

http://api.symfony-3.dev/app_dev.php/posts

returns:

[{
    "id": 1,
    "title": "first post title",
    "body": "first post body"
},
{
    "id": 2,
    "title": "second post title",
    "body": "second post body"
}]

And so on.

The important thing is that the shape of the data is the same - unless you start playing with serialization groups.

To quickly summarise, when your object / entity is converted (serialized) from PHP to JSON, you can use annotations such as:

     * @Annotations\View(serializerGroups={
     *     "accounts_all",
     *     "users_summary"
     * })

To alter what fields are included or excluded from the JSON output. This is cool, and powerful, but be careful as this can also make your API code more difficult to maintain. An example of this problem will occur a little later in the series when we implement PUT functionality in the browser / front end code.

Pre-empting Pagination

For the moment we aren't implementing any pagination, filtering, or sorting. But this will be needed a little later on.

As covered in the previous video, it therefore makes sense to work with this in mind, and structure out querying accordingly. Therefore, our entity repository is going to return queries rather than results:

<?php

// /src/AppBundle/Entity/Repository/BlogPostRepository.php

namespace AppBundle\Entity\Repository;

use Doctrine\ORM\EntityRepository;

class BlogPostRepository extends EntityRepository
{
    public function createFindAllQuery()
    {
        return $this->_em->createQuery(
            "
            SELECT bp
            FROM AppBundle:BlogPost bp
            "
        );
    }

Which means in our controller action we do need to explicitly call the getResult method:

// /src/AppBundle/Controller/BlogPostsController.php

    public function cgetAction()
    {
        return $this->getBlogPostRepository()->createFindAllQuery()->getResult();
    }

Because both getAction and cgetAction need to access the repository, I have extracted the duplicated code to a private method:

// /src/AppBundle/Controller/BlogPostsController.php

    /**
     * @return BlogPostRepository
     */
    private function getBlogPostRepository()
    {
        return $this->get('crv.doctrine_entity_repository.blog_post');
    }

If unsure on this, we declared the service in the previous video.

Later on in this series, we will be able to pass the as-yet-unrun query into the paginator, which will add in the necessary offset and limits to return the requested results. This stops a potential problem whereby we might have always run a SELECT * FROM blah type query, and then sliced and diced the result. This would be one of those problems that likely didn't show itself in development, when we have say 50 records in our DB, but with 100,000 in production, suddenly the entire system crawls to a halt.

And that's largely it for the moment with regards to GET'ting a collection of BlogPosts. As ever with programming, all the hard work happens at front, and then the implementation is almost a formality.

Of course, changes will need to be made, and that is almost inevitable on any project, but for the moment this is good enough.

Code For This Video

Get the code for this video.

Episodes