Image of a mountain
A boilerplate for your custom web services.
Scroll to content

Use the REST extension as boilerplate

This tutorial will show how the extension can be used as a starting point for custom web services. The core of the own web service is the Handler. The Handler implements the \Cundd\Rest\HandlerInterface which provides the accessors to set and retrieve the current Request object and the method configureApiPaths().

You can find the tutorial extension under https://github.com/cundd/custom_rest. It uses namespaces and therefore requires at least TYPO3 version 6.0.

Configure the access

The following lines configure read and write access to all paths matching cundd-custom_rest-*. This allows calls to your-domain.com/rest/cundd-custom_rest-route, your-domain.com/rest/cundd-custom_rest-path and your-domain.com/rest/cundd-custom_rest-whatever.

plugin.tx_rest.settings.paths {
    400 {
        path = cundd-custom_rest-*

        read = allow
        write = allow
    }
}

File: ext_typoscript_setup.txt

Configure an alias

The paths shown above are quite unesthetic, but enable the extensions flexibility. To still provide pretty URLs aliases can be registered.

plugin.tx_rest.settings.aliases {
    customhandler = cundd-custom_rest-custom_handler
}

File: ext_typoscript_setup.txt

This allows us to call your-domain.com/rest/customhandler instead of your-domain.com/rest/cundd-custom_rest-custom_handler.

Creating the Handler

Now lets have a look at the core of the custom extension: the Handler. To ship a Handler with your extension create a class in the format \YourVendor\YourExtensionName\Rest\Handler and make it implement \Cundd\Rest\HandlerInterface. REST's Object Manager will then automatically use this class for any request which path matches cundd-custom_rest-*.

The request accessor methods are used to make the current Request available to the Handler.

/**
 * Current request
 *
 * @var Request
 */
protected $request;

/**
 * Sets the current request
 *
 * @param \Cundd\Rest\Request $request
 * @return $this
 */
public function setRequest($request) {
    $this->request = $request;
    return $this;
}

/**
 * Returns the current request
 *
 * @return \Cundd\Rest\Request
 */
public function getRequest() {
    return $this->request;
}

File: Handler.php

The more interesting method is configureApiPaths(). Keep in mind that the REST extension is built with Bullet and this is the place where the actual routing is configured.

/**
 * Configure the API paths
 */
public function configureApiPaths() {
    $dispatcher = Dispatcher::getSharedDispatcher();

    /** @var Handler */
    $handler = $this;

    $dispatcher->registerPath($dispatcher->getRequest()->path(), function ($request) use ($handler, $dispatcher) {
        $handler->setRequest($request);

        # curl -X GET http://your-domain.com/rest/customhandler
        $dispatcher->registerGetMethod(function ($request) use ($dispatcher) {
            /** @var Request $request */
            return array(
                'path' => $request->path(),
                'uri'  => $request->uri(),
            );
        });

        $dispatcher->registerPath('subpath', function ($request) use ($handler, $dispatcher) {
            # curl -X GET http://your-domain.com/rest/customhandler/subpath
            $getCallback = function ($request) use ($handler, $dispatcher) {
                /** @var Request $request */
                return array(
                    'path' => $request->path(),
                    'uri'  => $request->uri(),
                );
            };
            $dispatcher->registerGetMethod($getCallback);

            # curl -X POST -d '{"username":"johndoe","password":"123456"}' http://your-domain.com/rest/customhandler/subpath
            $postCallback = function ($request) use ($handler) {
                /** @var Request $request */
                return array(
                    'path' => $request->path(),
                    'uri'  => $request->uri(),
                    'data' => $request->getSentData(),
                );
            };
            $dispatcher->registerPostMethod($postCallback);
        });
    });
}

The line $app->path($dispatcher->getPath(), function ... { sets the scope of the following definitions to the current request's path (i.e. cundd-custom_rest-path).

In the next line the current request will be stored in the Handlers request property (this is where the setRequest() method is used).

Now lets define the first route:

$app->get(function ($request) { instructs Bullet to execute the function when a GET request on the Handlers path is performed (i.e. GET http://your-domain.com/rest/customhandler). The function's return value will then be transformed into a response object of type \Bullet\Response and i.e. an array will be passed through json_encode() before.

$app->path('subpath', function ... { narrows the scope to match your-domain.com/rest/cundd-custom_rest-custom_handler/subpath, your-domain.com/rest/customhandler/subpath, ... and the following $app->get($getCallback) and $app->post($postCallback) register the callbacks for the according HTTP methods.

To access the data sent by the client, the dispatcher provides the method getSentData() which will return an array.

Finally the web service can be tested with

curl -X GET http://your-domain.com/rest/customhandler
curl -X GET http://your-domain.com/rest/customhandler/subpath
curl -X POST -H "Content-Type: application/json" -d '{"username":"johndoe","password":"123456"}' http://your-domain.com/rest/customhandler/subpath