AJAX with PSR-7

| 3 minutes psr-7 backend tutorial frontend

As stated in the previous article, you may also use PSR-7 for AJAX requests. However, the implementation in the backend and the frontend is different. This article explains how you setup so-called "routes" for backend AJAX requests and how eIDs look like for the frontend.


In old days, AJAX handlers were registered in ext_tables.php via \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::registerAjaxHandler(). Although this still works, you should refrain from this as this is deprecated since TYPO3 v8. As an alternative you should use routes. To achieve this, create the file Configuration/Backend/AjaxRoutes.php in your extension and register your routes:


return [
    'unique_identifier' => [
        'path' => '/unique/identifier',
        'target' => \FooBar\Baz\Controller\AjaxController::class . '::myAwesomeAction'
    'do_something' => [
        'path' => '/do/something',
        'target' => \FooBar\Baz\Controller\AjaxController::class . '::helloWorldAction'

Please be aware that the identifier and the path must be unique to avoid naming collisions.

After changing this file, the caches must be cleared.

After that, the routes are callable via AJAX. In an AMD module, you may call your action like this way:

    url: TYPO3.settings.ajaxUrls['unique_identifier'],
    method: 'GET',
    dataType: 'html',
    success: function(response) {

In this example, we let the action return HTML code. As the default content type for AJAX actions with PSR-7 is application/json in the backend, I'll show you how to change the content type:

public function helloWorldAction(
    \Psr\Http\Message\ServerRequestInterface $request,
    \Psr\Http\Message\ResponseInterface $response
) {
    $response->getBody()->write('<b>Hello <i>World</i></b>');
    $response = $response->withHeader('Content-Type', 'text/html; charset=utf-8');
    return $response;


In the frontend you still use eID. Those may also run with PSR-7 now, but this is not mandatory yet. The registration itself slightly changes, instead of passing a file you also pass a controller::action combination:

$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['fnord'] = \FooBar\Baz\Controller\FrontendAjaxController::class . '::fnordAction';

Thanks to the PSR-7 standard, the common "layout" of the action looks like the example from the backend:

public function fnordAction(
    \Psr\Http\Message\ServerRequestInterface $request,
    \Psr\Http\Message\ResponseInterface $response
) {
    $response->getBody()->write('I\'m content fetched via AJAX.');
    return $response;

In contrast to the backend, the default content type for eID remains text/html.

Previous Post Next Post