Dank der Flexibilität von TYPO3 gibt es sicher unzählige Wege um eine RESTful-API zu entwerfen (über einige davon haben wir auch schon in unserem Blog geschrieben, diese findest du hier). Bis zu TYPO3 Version 10, haben wir die TYPO3 Extension rest dafür verwendet). Diese funktioniert allerdings in TYPO3 10 nicht mehr und es ist fraglich, wann/ob diese jemals TYPO3 10 kompatibel wird. Aus diesem Grund waren wir auf der Suche nach neuen Möglichkeiten um eine RESTful-API auf Basis TYPO3 zu entwickeln. Nachdem wir uns verschiedene Konzept (zBsp. über eine SLIM Middleware oder über Plugins mit JSON-View wie auf "use TYPO3" beschrieben) überlegt und recherchiert haben, entschieden wir uns für die Routing-Lösung.
Wichtig dabei war für uns auch immer, dass man die Vorteile von extbase nützt und so nahe wie möglich am TYPO3-Standard bleibt. Also die Domain-Models ganz normal über TCA konfiguriert und wie man es gewohnt ist über das Backend verwaltet werden. Anfänglich haben wir hierfür einen eigenen Route Enhancer geschrieben, welcher die Plugins aufruft. Im Zuge unserer Recherche sind wir dann auf die Extension "Extbase Yaml Routes" von Borulko Serhii gestoßen:
Mit dieser Extension kann man eine RESTful-API entwickeln, die Routen per YAML-File konfigurieren und hast CRUD für seine Extbase-Objekte out of the box. Zusätzlich werden hier auch die bekannten TYPO3 Konzepte wie Route Enhancers, Extbase, JsonView, Middleware und co. verwendet. Zusätzlich wird auch gleich eine Javascript-Bibliothek zum Aufruf der API mitgeliefert.
RESTful API entwickeln
Nachdem die Extension über composer installiert und das TypoScript eingebunden wurde, geht es schon los. Zuerst muss in der Site-Config der entsprechende Route Enhancer hinzugefügt/eingebunden werden:
routeEnhancers:
ApplyRoutesCollection:
type: Routes
Definition der Routen
Über die Datei Routes.yml im Configuration-Verzeichnis der Extension werden die API-Routen (GET, POST, DELETE,...) definiert. Hierfür ein einfaches Beispiel:
va_rest_day-list:
path: api/v1/restdemo/days
controller: Various\VaRest\Controller\RestController::list
methods: GET
format: json
defaults:
plugin: Day
va_rest_day-detail:
path: api/v1/restdemo/days/{uid}
controller: Various\VaRest\Controller\RestController::detail
methods: GET
format: json
defaults:
plugin: Day
requirements:
uid: \d+
va_rest_win-subscribe:
path: api/v1/restdemo/subscribe
controller: Various\VaRest\Controller\RestController::subscribe
methods: POST
format: json
defaults:
plugin: Subscribe
Plugin anlegen
Danach müssen noch die Plugins angelegt werden (in der ext_localconf.php):
ExtensionUtility::configurePlugin(
'va_rest',
'Day',
[
RestController::class => 'detail, list',
],
[]
);
ExtensionUtility::configurePlugin(
'va_rest',
'Subscribe',
[
RestController::class => 'subscribe',
],
[
RestController::class => 'subscribe',
]
);
Controller action - Where the magic happens
Wie bereits in der Einleitung erwähnt, haben wir vorab natürlich ganz normale extbase-Objekte angelegt und definiert (SQL-Definition, TCA, Models und Repositories). Mit der obigen Konfiguration werden nun automatisch die jeweiligen Controller-Actions aufgerufen. An dieser Stelle sei noch gesagt, dass wir für unsere APIs immer json als Dateiformat verwenden. Da in unserem Beispiel auch FileReferences (Bilder) verwendet werden, verwenden wir auch die JsonView, damit wir unser Objekt noch bearbeiten können (siehe weiter unten). Auch dies ist ein Konzept, dass dem einen oder anderen bereits aus TYPO3 bekannt sein sollte.
<?php
declare(strict_types=1);
namespace Various\VaRest\Controller;
use TYPO3\CMS\Core\Http\HtmlResponse;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use Various\VaRest\Domain\Repository\DayRepository;
use Various\VaRest\Utility\RestUtility;
use Various\VaRest\Mvc\View\JsonView;
class RestController extends ActionController
{
/**
* @var \Various\VaRest\Mvc\View\JsonView
*/
protected $view;
/**
* @var string
*/
protected $defaultViewObjectName = JsonView::class;
protected DayRepository $dayRepository;
public function __construct(DayRepository $dayRepository)
{
$this->dayRepository = $dayRepository;
}
public function detailAction()
{
if(!$this->request->hasArgument('uid')) {
return new HtmlResponse('Parameter Missing', 400);
}
$day = $this->dayRepository->findByUid(intval($this->request->getArgument('uid')));
if(is_null($day)) {
return new HtmlResponse('Bad Parameter', 400);
}
$this->view->setVariablesToRender(['day']);
$this->view->assign('day', $day);
}
public function listAction()
{
$this->view->setVariablesToRender(['days']);
$this->view->assign('days', $this->dayRepository->findAll());
}
public function subscribeAction()
{
return RestUtility::subscribe($this->request);
}
}
json-Darstellung
Nun definieren wir noch wie unser Day-Objekt in der JsonView gerendert wird:
<?php
declare(strict_types=1);
namespace Various\VaRest\Mvc\View;
use TYPO3\CMS\Extbase\Mvc\View\JsonView as ExtbaseJsonView;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
use Various\VaRest\Domain\Model\Day;
class JsonView extends ExtbaseJsonView
{
/**
* @var array
*/
protected $configuration = [
'days' => [
'_descendAll' => [
'_exclude' => ['pid'],
'_descend' => [
'image' => [
'_descendAll' => [
'_only' => ['originalResource'],
'_descend' => [
'originalResource' => [
'_only' => ['publicUrl'],
],
],
],
],
],
],
],
'day' => [
'_exclude' => ['pid'],
'_descend' => [
'image' => [
'_descendAll' => [
'_only' => ['originalResource'],
'_descend' => [
'originalResource' => [
'_only' => ['publicUrl'],
],
],
],
],
],
],
];
/**
* Transforming ObjectStorages to Arrays for the JSON view
*
* @param mixed $value
*/
protected function transformValue($value, array $configuration): array
{
if ($value instanceof ObjectStorage) {
$value = $value->toArray();
}
return parent::transformValue($value, $configuration);
}
}
Zusammenfassung
Mit obigen Beispiel kann also ziemlich einfach und flexibel eine RESTful-API mit TYPO3 erstellt werden. Auch eine Absicherung mittels Login oder Basic Auth ist einfach möglich. Man kann auch eigene Middlewares entwickeln, welche man hier gut einsetzen kann.
Zum Schluss möchte ich auch noch auf POSTMAN hinweisen. Dies sollte jedem Backend-Entwickler ein Begriff sein, kann man damit seine API definieren, testen und weitergeben (als Collection). Wir legen hier für jede API immer eine eigene Collection an, welche dann im git-Repository liegt und jeder Entwickler an einem Projekt kann sich sehr schnell einen Überblick über die API verschaffen. Auch kann für den Aufruf zum Beispiel direkt Programmier-Code daraus exportiert werden.

Aus der Reihe TYPO3 Tipps und Tricks
- PSR-15 Middleware am Beispiel Mailchimp Webhook
- Ajax mit TYPO3 – so funktionierts!
- Microsoft SQL Server (MSSQL) und TYPO3 in einem Docker-Container
- Manueller/Programmatischer Login in Controller-Action (TYPO3 9)
- Cache für einzelne Extbase-Objekte leeren
- Grideditor für TYPO3 Inhaltselemente
Nützliche Links / Quellen
- RESTful-API-Design
- Extbase Yaml Routes
- TYPO3 Routing und Route Enhancers
- REST web service for TYPO3 CMS - bis TYPO3 Version 10
Weitere interessante Beiträge zum Thema TYPO3 findest du hier.
Wir entwickeln digitale Lösungen mit Leidenschaft
Warum wir das tun? Weil die Verwirklichung Ihrer Vision unser größter Anspruch und die schönste Anerkennung ist. Deshalb nehmen wir uns gerne ausreichend Zeit für die Realisierung Ihres digitalen Projekts.
Kontaktieren Sie uns, wir sind gerne für Ihre Fragen da: