The eZ Publish 5 REST API comes with a framework that makes it quite easy to extend the API for your own needs.

While most of what can be found here will still apply in the future, the structure of the REST API and its components will evolve before the actual release.

Requirements

As of version 2013.7, REST routes are required to use the eZ Publish 5 REST API prefix, /api/ezp/v2. You can create new resources below this prefix.

To do so, you will/may need to create

Controller

To create a REST controller, you need to extend the ezpublish_rest.controller.base service, as well as the eZ\Publish\Core\REST\Server\Controller class.

services:
    myRestBundle.controller.default:
        class: My\Bundle\RestBundle\Rest\Controller\Default
        parent: ezpublish_rest.controller.base

Let's create a very simple controller, that has a sayHello() method, that takes a name as an argument.

namespace My\Bundle\RestBundle\Rest\Controller;
 
use eZ\Publish\Core\REST\Server\Controller as BaseController;
 
class Default extends BaseController
{
    public function sayHello( $name )
    {
        // @todo Implement me
    }
}

Route

As said earlier, your REST routes are required to use the REST URI prefix. To do so, the easiest way is to import your routing file using this prefix.

myRestBundle_rest_routes:
    resource: "@MyRestBundle/Resources/config/routing_rest.yml"
    prefix:   %ezpublish_rest.path_prefix%

Using a distinct file for REST routes allows you to use the prefix for all this file's routes without affecting other routes from your bundle.

Next, you need to create the REST route. We need to define the route's controller as a service since our controller was defined as such.

myRestBundle_hello_world:
    pattern: /my_rest_bundle/hello/{name}
    defaults:
        _controller: myRestBundle.controller.default:sayHello
    methods: [GET]

Controller action

Unlike standard Symfony 2 controllers, the REST ones don't return an HttpFoundation\Response object, but a ValueObject. This object will during the kernel run be converted, using a ValueObjectVisitor, to a proper Symfony 2 response. One benefit is that when multiple controllers return the same object, such as a Content or a Location, the visitor will be re-used.

Let's say that our Controller will return a My\Bundle\RestBundle\Rest\Values\Hello

namespace My\Bundle\RestBundle\Rest\ValueObject;
 
class Hello
{
    public $name;
 
    public function __construct( $name )
    {
        $this->name = $name;
    }
}

We will return an instance of this class from our sayHello() controller method.

namespace My\Bundle\RestBundle\Rest\Controller;

use eZ\Publish\Core\REST\Server\Controller as BaseController;
use My\Bundle\RestBundle\Rest\Controller\Values\Hello as HelloValue;

class Default extends BaseController
{
    public function sayHello( $name )
    {
        return new HelloValue( $name );
    }
}

And that's it. Converting this object requires that we create a ValueObjectVisitor.

ValueObjectVisitor

A ValueObjectVisitor will take a Value returned by a REST controller, whatever the class, and will transform it into data that can be converted, either to json or XML. Those visitors are registered as services, and tagged with ezpublish_rest.output.value_object_visitor. The tag attribute says which class this Visitor applies to.

Let's create the service for our ValueObjectVisitor first.

services:
    myRestBundle.value_object_visitor.hello:
        parent: ezpublish_rest.output.value_object_visitor.base
        class: My\Bundle\RestBundle\Rest\ValueObjectVisitor\Hello
        tags:
            - { name: ezpublish_rest.output.value_object_visitor, type: My\Bundle\RestBundle\Rest\Values\Hello }

Let's create our visitor next. It must extend the eZ\Publish\Core\REST\Common\Output\ValueObjectVisitor abstract class, and implement the visit() method.
It will receive as arguments:

namespace My\Bundle\RestBundle\Rest\ValueObjectVisitor;


use eZ\Publish\Core\REST\Common\Output\ValueObjectVisitor;
use eZ\Publish\Core\REST\Common\Output\Generator;
use eZ\Publish\Core\REST\Common\Output\Visitor;


class Hello extends ValueObjectVisitor
{
    public function visit( Visitor $visitor, Generator $generator, $data )
    {
    }
}