Testing Apigility Code-Connected REST APIs

October 11, 2013

The recently announced Apigility arrives just when I'm experimenting ways to create and maintain my own set of APIs. So I could not resist to giving this new Zend tool a try. Before reading the post, please watch the Apigility Demo from Matthew Weier O'Phinney on Vimeo.

The test I'm about to describe involves the creation of a "Fortune Cookie" REST API. I've tried to keep the code as simple as I could. It lacks of basic stuff but it's meant to be that way.

First thing, I've installed Apigility following the readme on GitHub, opened the admin interface and clicked on the "Get Started!" button. Things are pretty straightforward: added the new API clicking on the "Create New API" button located in the top-right corner, typed in FortuneCookie and pressed the "Create API". Next thing, I've added the new Code-Connected REST service called OpenCookie. So far so good.

At this point, checking the filesystem, I found these files:

  • module/FortuneCookie/config/module.config.php
  • module/FortuneCookie/src/FortuneCookie/V1/Rest/OpenCookie/OpenCookieCollection.php
  • module/FortuneCookie/src/FortuneCookie/V1/Rest/OpenCookie/OpenCookieEntity.php
  • module/FortuneCookie/src/FortuneCookie/V1/Rest/OpenCookie/OpenCookieResource.php

This is what you'll see in your favorite IDE:

Apigility created a new Zend Framework 2 module called FortuneCookie with some files in and added the module to the modules array in config/application.config.php. The first thing I've noticed is that Apigility relies only on files, no database is used to manage configuration or other things. This is a perfect solution to easily deploy or update new APIs and to keep track of changes using a VCS.

Since I've created a Code-Connected REST service, I needed to add some code somewhere. The class I'm interested in editing is OpenCookieResource. The class contains a list of methods throwing exceptions all over. Since the class extends ZF\Rest\AbstractResourceListener I've replaced everything with this code:

<?php
namespace FortuneCookie\V1\Rest\OpenCookie;

use ZF\ApiProblem\ApiProblem;
use ZF\Rest\AbstractResourceListener;
use Zend\Paginator\Adapter\ArrayAdapter;

class OpenCookieResource extends AbstractResourceListener
{
    private function getData()
    {
        return array(
            1 => array(
                'open_cookie_id' => 1,
                'text' => 'I may throw up on ya.',
                'who' => 'Leonard \'Bones\' McCoy',
            ),
            2 => array(
                'open_cookie_id' => 2,
                'text' => 'I think these things are pretty safe.',
                'who' => 'James T. Kirk'
            ),
            3 => array(
                'open_cookie_id' => 3,
                'text' => 'Well, I hate to break this to you, but Starfleet operates in space.',
                'who' => 'James T. Kirk'
            ),
            4 => array(
                'open_cookie_id' => 4,
                'text' => 'Yeah. Well, I got nowhere else to go. The ex-wife took the whole damn planet in the divorce. All I got left is my bones.',
                'who' => 'Leonard \'Bones\' McCoy'
            ),
            5 => array(
                'open_cookie_id' => 5,
                'text' => 'If you eliminate the impossible, whatever remains, however improbable, must be the truth.',
                'who' => 'Spock'
            )
        );
    }

    /**
     * Fetch a resource
     */
    public function fetch($id)
    {
        return new OpenCookieEntity($this->getData()[$id]);
    }

    /**
     * Fetch all or a subset of resources
     */
    public function fetchAll($params = array())
    {
        $adapter = new ArrayAdapter($this->getData());
        $collection = new OpenCookieCollection($adapter);
        return $collection;
    }
}

Also, at this point I needed to change the OpenCookieEntity class:

<?php
namespace FortuneCookie\V1\Rest\OpenCookie;

class OpenCookieEntity{
    private $open_cookie_id;
    private $text;
    private $who;

    public function __construct(array $entity = null)
    {
        if ($entity !== null && is_array($entity)) {
            $this->open_cookie_id = $entity['open_cookie_id'];
            $this->text = $entity['text'];
            $this->who = $entity['who'];
        }
    }

    public function getOpenCookieId()
    {
        return $this->open_cookie_id;
    }

    public function getText()
    {
        return $this->text;
    }

    public function getWho()
    {
        return $this->who;
    }
}

The only problem I had during the test was an error I kept getting when calling the API:

{
    "problemType": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html",
    "title": "Internal Server Error",
    "httpStatus": 500,
    "detail": "Unable to extract FortuneCookie\\V1\\Rest\\OpenCookie\\OpenCookieEntity; no hydrator registered"
}

After some research I added 'hydrator' => 'ClassMethods' to the module/FortuneCookie/config/module.config.php and the problem was gone:

Now, it could be that a quote from a Star Trek movie may not by considered a "fortune", but, besides that, things just work perfectly. I'm able to view the paginated collection calling http://local.apigility.org/open-cookie and the single content calling http://local.apigility.org/open-cookie/2 (where 2 is the index of the content).

Below some screenshots of the results:

Lorenzo Ferrara

Posts Twitter Google+