Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
This course is archived!
This tutorial uses a deprecated micro-framework called Silex. The fundamentals of REST are still ? valid, but the code we use can't be used in a real application.

GET /programmers: A collection of Programmers

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.

Start your All-Access Pass
Buy just this tutorial for $12.00

GET /programmers: A collection of Programmers

We now have 2 URLs and so 2 resources:

  • /api/programmers, which represents a collection of resources (i.e. all programmers);
  • /api/programmers/{nickname}, which represents one programmer.

Actually, we can POST to the /api/programmers resource, but we can’t GET it yet. And nothing says that we have to support the GET method for a resource. But we’ll add it for two reasons. First, I’ll pretend that our imaginary iPhone app needs it. And second, API users tend to assume that you can GET most any resource. If we make this possible, our API is that much more predictable and friendly.

Coding up our Test

Like always, let’s start by updating our testing script to try the new endpoint:

// testing.php
// ...

// 3) GET a list of all programmers
$request = $client->get('/api/programmers');
$response = $request->send();

echo $response;
echo "\n\n";

Creating the Route

Next, create a new route that points to a new listAction method in our ProgrammerController class:

// src/KnpU/CodeBattle/Controller/Api/ProgrammerController.php
// ...

protected function addRoutes(ControllerCollection $controllers)
{
    // the 2 other routes ...

    $controllers->get('/api/programmers', array($this, 'listAction'));
}

Creating the Endpoint

I’ll copy the showAction and modify it for listAction. First, remove the $nickname argument, since there’s no {nickname} in this new URI. Next, query for all programmers using another method from my ORM. The key is that this gives us an array of Programmer objects:

// src/KnpU/CodeBattle/Controller/Api/ProgrammerController.php
// ...

public function listAction()
{
    $programmers = $this->getProgrammerRepository()->findAll();
    // ...
}

Like before, we need to turn each Programmer into an array. I really don’t want to duplicate this logic. Instead, create a new `serializeProgrammer function right in this class that converts a Programmer object into an array. This is still manual, but later I’ll show you some fancier ways to do this:

// src/KnpU/CodeBattle/Controller/Api/ProgrammerController.php
// ...

private function serializeProgrammer(Programmer $programmer)
{
    return array(
        'nickname' => $programmer->nickname,
        'avatarNumber' => $programmer->avatarNumber,
        'powerLevel' => $programmer->powerLevel,
        'tagLine' => $programmer->tagLine,
    );
}

Now, use this to build a big array of the programmers in listAction:

// src/KnpU/CodeBattle/Controller/Api/ProgrammerController.php
// ...

public function listAction()
{
    $programmers = $this->getProgrammerRepository()->findAll();
    $data = array('programmers' => array());
    foreach ($programmers as $programmer) {
        $data['programmers'][] = $this->serializeProgrammer($programmer);
    }

    $response = new Response(json_encode($data), 200);
    $response->headers->set('Content-Type', 'application/json');

    return $response;
}

And make sure to also update showAction to use serializeProgrammer:

// src/KnpU/CodeBattle/Controller/Api/ProgrammerController.php
// ...

public function showAction($nickname)
{
    // ...

    // replace the manual creation of the array with this function call
    $data = $this->serializeProgrammer($programmer);

    // ...
}

Cool - let’s try it!

$ php testing.php
HTTP/1.1 200 OK
...
Content-Type: application/json

{
    "programmers": [
        {
            "nickname":"ObjectOrienter14",
            "avatarNumber":"5",
            "powerLevel":"0",
            "tagLine":null
        },
        {
            "nickname":"ObjectOrienter795",
            "avatarNumber":"5",
            "powerLevel":"0",
            "tagLine":"a test dev!"
        }
    ]
}

What JSON Structure to Use?

Awesome! So why did I put the data under a programmers key? Actually, no special reason, I just invented this standard. I could have structured my JSON however I wanted.

And actually, there are some pre-existing standards that exist on the web for organizing your JSON structures. These answer questions like, “should I put the data under a programmers key?” or “how should I organize details on how to paginate through the results?”.

This is real important stuff, and we’ll go into more detail later. For now, we just have to follow one golden rule: find a standard and be consistent.

Now rewind back 10 seconds and listen to that again at least 5 times. Consistency people!

Leave a comment!

2
Login or Register to join the conversation
Tom Avatar

Where are these programmer objects coming from? I noticed a directory called 'Data' with a code_battles.sqlite file but its empty.

Reply
MolloKhan Avatar MolloKhan | SFCASTS | Tom | posted 4 years ago | edited

Hey Tom

Those programmer records are being created by hitting our POST endpoint sending some hardcoded data. Give it a check to chapter 6

Cheers!

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

This tutorial uses a deprecated micro-framework called Silex. The fundamentals of REST are still ? valid, but the code we use can't be used in a real application.

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "silex/silex": "~1.0", // v1.3.2
        "symfony/twig-bridge": "~2.1", // v2.7.3
        "symfony/security": "~2.4", // v2.7.3
        "doctrine/dbal": "^2.5.4", // v2.5.4
        "monolog/monolog": "~1.7.0", // 1.7.0
        "symfony/validator": "~2.4", // v2.7.3
        "symfony/expression-language": "~2.4" // v2.7.3
    },
    "require-dev": {
        "behat/mink": "~1.5", // v1.5.0
        "behat/mink-goutte-driver": "~1.0.9", // v1.0.9
        "behat/mink-selenium2-driver": "~1.1.1", // v1.1.1
        "behat/behat": "~2.5", // v2.5.5
        "behat/mink-extension": "~1.2.0", // v1.2.0
        "phpunit/phpunit": "~5.7.0", // 5.7.27
        "guzzle/guzzle": "~3.7" // v3.9.3
    }
}
userVoice