Version 1.0 - Eine vollständige, erweiterbare GraphQL-API für REDAXO CMS mit SDL-basierter Schema-Definition.
- 🧩 SDL-basierte Schema-Erweiterung - Definiere GraphQL-Schemas mit SDL-Dateien
- 🔄 Unbegrenzte Query-Verschachtelung - 1:n und n:1 Beziehungen automatisch aufgelöst
- 📊 Automatische YForm-Integration - Alle YForm-Tabellen werden automatisch als GraphQL-Typen verfügbar
- 🔗 Intelligente Slug-Generierung - Automatische URL-Generierung über das URL-Addon
- 🌐 Public Headless CMS - Direkte API-Nutzung ohne Backend-Authentifizierung
- 🔒 Granulare Berechtigungen - Typ-basierte Zugriffskontrolle mit automatischer Schema-Generierung
- 📡 Webhooks - Cache-Invalidierung und externe Benachrichtigungen
- ⚡ Intelligentes Caching - Schema- und Query-Caching für optimale Performance
- 🎯 Erweiterte GraphQL Playground - CodeMirror-Integration mit Autovervollständigung
- 📈 Detaillierte Statistiken - Query-Logging und Performance-Monitoring
- 🔒 CORS & Domain-Beschränkungen - Sichere API-Nutzung in Frontend-Anwendungen
- 🔄 Mutationen - Unterstützung für GraphQL-Mutationen zur Datenmanipulation
- Installation & Schnellstart
- API-Endpoints
- Schema-Erweiterung mit SDL
- Automatische YForm-Integration
- Unbegrenzte Query-Verschachtelung
- Webhooks
- Berechtigungen & Sicherheit
- Intelligentes Caching
- GraphQL Playground
- Query-Beispiele
- Statistiken & Monitoring
- Entwicklung & Extension Points
- Konfiguration
- Migration & Breaking Changes
- Weiterführende Ressourcen
- Support & Community
- Lizenz
Installieren Sie das Addon über den REDAXO Installer oder manuell:
- Lade das Addon von GitHub herunter und entpacke es in den
src/addons/rexql
Ordner deines REDAXO-Projekts. - Installiere die Abhängigkeiten im
src/addons/rexql
Ordner über Composer:
cd src/addons/rexql
composer install
Aktiviere das Addon im REDAXO Backend.
-
rexQL → Konfiguration:
- ✅ API-Endpoint aktivieren
- ✅ CORS-Origins für deine Domain(s) eintragen
-
rexQL → Berechtigungen:
- Erstelle einen API-Key ODER deaktiviere die Authentifizierung für öffentliche APIs
- Falls API-Keys verwendet werden, wähle Berechtigung für gewünschte Typen (z.B.
article
,media
)
- Falls API-Keys verwendet werden, wähle Berechtigung für gewünschte Typen (z.B.
- Erstelle einen API-Key ODER deaktiviere die Authentifizierung für öffentliche APIs
-
Testen:
- Öffne rexQL → Playground
- Führe eine Test-Query aus:
{
articles(limit: 3) {
id
name
createdate
}
}
POST /index.php?rex-api-call=rexql
POST /api/rexql/
Beispiel .htaccess-Regel:
RewriteRule ^api/rexql/?$ index.php?rex-api-call=rexql [L,QSA]
Beispiel Nginx-Regel:
location /api/rexql {
rewrite ^/api/rexql(.*) /index.php?rex-api-call=rexql$1 last;
}
Die wichtigste Neuerung in v1.0 ist die SDL-basierte Schema-Definition. Erweitere die GraphQL-API über REDAXO Extension Points:
Das Core-Schema in data/schema.graphql
definiert alle REDAXO Core-Typen.
Das gesamte Schema kann im Playground oder in data/schema.graphql
eingesehen werden.
Das Core-Schema beinhaltet folgende Typen:
article
: Artikel-Typ mit Beziehungen zulanguage
,template
undslices
.config
language
media
: Medientyp mit Beziehungen zumediaCategory
.mediaCategory
: Mediacategory-Typ mit Beziehungen zuchildren
(Unterkategorien).module
: Modultyp mit Beziehungen zuslices
.navigationItem
route
slice
: Slice-Typ mit Beziehungen zumodule
,article
undlanguage
.system
: System-Informationen wie REDAXO-Version und Server-Name.template
: Template-Typ mit Beziehungen zuarticles
.wildcard
: Wildcard-Typ für Sprog-Übersetzungen.- sowie Yform-Tabellen wie
rex_news
,rex_event
, etc.
type Query {
# Artikel-Queries
article(id: ID!, clangId: Int, ctypeId: Int): article
articles(
clangId: Int
categoryId: Int
status: Boolean
limit: Int
): [article]
# Media-Queries
media(id: ID!): media
medias(categoryId: Int): [media]
# usw...
}
Erweitere das Schema über den REXQL_EXTEND
Extension Point.
Der ExtensionPoint sollte einen Array zurückgeben, der die sdl
und rootResolvers
enthält.
Achtung: SDL
erweitern und nicht überschreiben!
Desweitern kann man mit $ep->getParams()
auf die Parameter des ExtensionPoints zugreifen, welcher den aktuellen Kontext sowie das Addon selbst enthält.
<?php
// In deinem Addon's boot.php
rex_extension::register('REXQL_EXTEND', function (rex_extension_point $ep) {
$extensions = $ep->getSubject();
// Erweitere das SDL-Schema
$extensions['sdl'] .= '
extend type Query {
customData(filter: String): [CustomType]
}
type CustomType {
id: ID!
title: String
content: String
publishedAt: String
}
';
// Registriere Custom Resolver
$extensions['rootResolvers']['query']['customData'] = function($root, $args) {
// Deine Custom Logic hier
return [
['id' => 1, 'title' => 'Test', 'content' => 'Beispiel'],
];
};
return $extensions;
});
Für komplexere Anforderungen erweitere die ResolverBase
Klasse:
<?php
use FriendsOfRedaxo\RexQL\Resolver\ResolverBase;
class CustomResolver extends ResolverBase
{
public function getData(): array|null
{
$this->table = 'custom_table';
// Automatische Relation-Definition
$this->relations = [
'rex_media' => [
'alias' => 'image',
'type' => 'hasOne',
'localKey' => 'image_id',
'foreignKey' => 'id',
'relations' => [
'rex_media_category' => [
'alias' => 'category',
'type' => 'hasOne',
'localKey' => 'category_id',
'foreignKey' => 'id',
]
]
]
];
// Field Resolver für berechnete Felder
$this->fieldResolvers = [
$this->table => [
'fullUrl' => function($row): string {
return rex::getServer() . $row['custom_table_path'];
}
]
];
$results = $this->query();
return $this->typeName === 'customList' ? $results : $results[0] ?? null;
}
}
// Schema-Registrierung
rex_extension::register('REXQL_EXTEND', function (rex_extension_point $ep) {
$extensions = $ep->getSubject();
$extensions['sdl'] .= '
extend type Query {
customItem(id: ID!): CustomItem
customList(limit: Int): [CustomItem]
}
type CustomItem {
id: ID!
name: String
fullUrl: String
image: media
}
';
$resolver = new CustomResolver();
$extensions['rootResolvers']['query']['customItem'] = $resolver->resolve();
$extensions['rootResolvers']['query']['customList'] = $resolver->resolve();
return $extensions;
});
Selbstverständlich kann man auch komplexere Logik in den Resolvern implementieren, wie z.B. Datenbankabfragen, externe API-Calls oder komplexe Berechnungen. Wenn man komplett eigene Resolver-Klassen erstellen möchte, dann hilft ev. folgendes:
- das Interface
FriendsOfRedaxo\RexQL\Resolver\Interface
, welches die MethodengetData()
undgetTypeName()
definiert. - die Klasse
FriendsOfRedaxo\RexQL\Resolver\ResolverBase
, die bereits viele nützliche Methoden und Eigenschaften bereitstellt, wie z.B.query()
,checkPermissions()
,log()
,error()
undgetFields()
. - die Bibliothek
webonyx/graphql-php
, dierexql
integriert. Darin spezielle die KlasseGraphQL\Type\Definition\ResolveInfo
, die Informationen über die GraphQL-Query enthält, wie z.B. die angeforderten Felder und Argumente. - GraphQL.org für allgemeine GraphQL-Konzepte und Best Practices.
Alle YForm-Tabellen werden automatisch als GraphQL-Typen verfügbar gemacht (Berechtigungen beachten!).
Damit kannst du YForm-Daten direkt über GraphQL abfragen, ohne manuelle Schema-Definitionen.
Ist eine YForm-Tabelle mit einem Profil des REDAXO URL-Addons verknüpft, kann man auch die von URL generierten Slugs für einen Datensatz abfragen. Dabei versucht rexQL, automatisch den korrekten Slug-Namespace zu verwenden, der im YForm-Profil definiert ist. Um sicher zu gehen, dass der korrekte Namespace verwendet wird, kann man den slugNamespace
-Parameter in der Query angeben.
Gut zu wissen: die routes
-Query gibt alle Routen aus, auch für eine YForm-Tabelle, die mit dem URL-Addon verknüpft ist.
# YForm-Tabelle "rex_news" wird automatisch zu:
extend type Query {
rexNewsDataset(id: ID!, slugNamespace: String): rexNews
rexNewsCollection(
status: Boolean
where: String
orderBy: String
offset: Int
limit: Int
slugNamespace: String
): [rexNews]
}
type rexNews {
id: ID
slug: String # Automatisch generiert via URL-Addon
title: String
content: String
publishDate: String
status: String
author: rexUser # YForm-Relationen werden automatisch aufgelöst
}
# Einzelnen Datensatz abrufen
{
rexNewsDataset(id: 1) {
id
title
content
slug
author {
name
email
}
}
}
# Collection mit Filterung
{
rexNewsCollection(
status: true
where: "publish_date > '2024-01-01'"
orderBy: "publish_date DESC"
limit: 10
) {
id
title
slug
publishDate
}
}
Wenn das REDAXO URL-Addon installiert ist, kann der von URL generierte Slug abgefragt werden, wenn die Tabelle mit einem Profil des URL-Addons verknüpft ist:
{
rexNewsDataset(id: 1, slugNamespace: "news") {
id
title
slug # Automatisch: "/news/mein-artikel-titel"
}
}
Das v1.0 Resolver-System löst automatisch 1:n und n:1 Beziehungen ohne zusätzliche SQL-Queries auf:
{
article(id: 1) {
id
name
template {
id
name
}
slices {
id
value1
module {
id
name
}
}
}
}
Webhooks ermöglichen Cache-Invalidierung und externe Benachrichtigungen:
- rexQL → Webhooks
- Webhook-URL hinzufügen:
https://ihre-app.de/api/webhook
- Events auswählen:
article_update
,media_update
, etc.
{
"event": "article_update",
"timestamp": "2024-08-01T10:00:00Z",
"data": {
"id": 1,
"table": "rex_article",
"action": "update"
}
}
// In deiner Frontend-App
app.post('/api/webhook', (req, res) => {
const { event, data } = req.body
if (event === 'article_update') {
// Cache invalidieren
cache.del(`article:${data.id}`)
// Static Site Regeneration triggern
regeneratePage(`/articles/${data.id}`)
}
res.json({ success: true })
})
Berechtigungen werden automatisch für alle Schema-Typen generiert:
Verfügbare Berechtigungen:
Article
- Zugriff aufrex_article
Config
- Zugriff aufrex_config
Language
- Zugriff aufrex_language
Media
- Zugriff aufrex_media
MediaCategory
- Zugriff aufrex_media_category
Module
- Zugriff aufrex_module
NavigationItem
- Zugriff aufrex_article
um verschachtelte Navigationen zu ermöglichenRoute
- Zugriff aufrex_article
,yrewrite
undurl
um alle möglichen Routen auszulesenSlice
- Zugriff aufrex_article_slice
um Slices zu ladenSystem
- Zugriff auf System-Informationen von REDAXOTemplate
- Zugriff aufrex_template
Wildcard
- Zugriff aufsprog
um Wildcards zu laden
- rexQL → Berechtigungen → Hinzufügen
- Domain-Beschränkungen:
ihre-domain.de,localhost
- Berechtigungen auswählen:
article
,media
,rexNews
- API-Key kopieren:
rexql_abc123...
// Domain-beschränkter API-Key (Frontend-sicher)
const client = new GraphQLClient('/api/rexql/', {
headers: {
'X-API-KEY': 'rexql_abc123...',
'Content-Type': 'application/json'
}
})
const { data } = await client.request(
`
query GetArticles($limit: Int) {
articles(limit: $limit) {
id
name
slug
}
}
`,
{ limit: 10 }
)
// Für Backend-authentifizierte Requests
const proxyClient = new GraphQLClient('/index.php?rex-api-call=proxy', {
headers: {
Authorization: 'Bearer ' + sessionToken,
'X-Public-Key': 'rexql_pub_xyz789...'
}
})
Das GraphQL-Schema wird automatisch gecacht und nur bei Änderungen neu generiert.
Wiederholte Queries werden gecacht (Standard: 5 Minuten; konfigurierbar in den Backend-Einstellungen):
# Cache umgehen für Entwicklung
curl -X POST "/api/rexql/?noCache=1" \
-H "X-API-KEY: rexql_abc123..." \
-d '{"query": "{ articles { id name } }"}'
// Programmatische Cache-Kontrolle
use FriendsOfRedaxo\RexQL\Cache;
// Kompletten Cache löschen
Cache::invalidateAll();
// Nur Schema-Cache löschen
Cache::invalidateSchema();
// Nur Query-Cache löschen
Cache::invalidateQueries();
Der erweiterte Playground bietet:
- Schema-Explorer: Vollständige Schema-Dokumentation
- CodeMirror-Editor: Syntax-Highlighting und Autovervollständigung
- Query-Validation: Echtzeit-Fehlerprüfung
- Variable-Support: JSON-Variablen für Queries
- rexQL → Playground öffnen
- API-Key eingeben
- Query schreiben mit Autovervollständigung:
query GetArticleWithContent($id: ID!) {
article(id: $id) {
id
name
slices {
id
value1
module {
name
}
}
}
}
- Variablen definieren:
{
"id": "1"
}
# Artikel mit verschachtelten Beziehungen
{
articles(limit: 5, status: true) {
id
name
slug
template {
name
}
slices {
value1
value2
module {
name
}
}
}
}
# Medien mit Kategorien
{
medias(categoryId: 1) {
id
filename
title
category {
name
parentId
}
}
}
# Navigation-Struktur
{
navigation(categoryId: 1, depth: 2, nested: true) {
id
name
slug
children {
id
name
slug
}
}
}
# System-Informationen
{
system {
version
serverName
startArticleId
domainLanguages {
id
name
code
}
}
}
# News-Artikel mit Autor und Kategorien
{
rexNewsCollection(status: true, orderBy: "publish_date DESC", limit: 10) {
id
title
slug
publishDate
author {
name
email
}
categories {
name
}
}
}
# Event-Details mit Location
{
rexEventDataset(id: 1) {
id
title
description
startDate
endDate
location {
name
address
city
}
}
}
rexQL → Statistiken zeigt:
- Häufigste Queries
- Performance-Metriken
- API-Key Nutzung
- Fehler-Logs
# Debug-Informationen in Antworten
{
"data": { ... },
"extensions": {
"executionTime": "25.57ms",
"memoryUsage": "1.29 KiB",
"cacheStatus": "hit"
}
}
REXQL_EXTEND
- Haupt-Extension Point für Schema und ResolverREXQL_EXTEND_FIELD_RESOLVERS
- Custom Field ResolverREXQL_EXTEND_TYPE_RESOLVERS
- Custom Type Resolver
Die ResolverBase
Klasse bietet hilfreiche Methoden:
// Automatische Query-Generierung
$results = $this->query();
// Berechtigungsprüfung
$this->checkPermissions($typeName);
// Logging
$this->log('Debug-Nachricht');
// Fehler-Behandlung
$this->error('Fehlermeldung');
// Field-Selection aus GraphQL-Query
$fieldSelection = $this->info->getFieldSelection(5); // 5 ist die maximale Tiefe
$fields = $this->getFields($table /* oder */ $typeName, $fieldSelection);
rexQL → Konfiguration:
- API-Endpoint aktivieren - Ein/Aus
- Authentifizierung erforderlich - Für geschützte APIs
- CORS-Origins -
domain1.de,domain2.de,localhost:3000
- Rate Limiting - Anfragen pro Minute
- Query-Tiefe-Limit - Schutz vor DoS-Angriffen
- Debug-Modus - Detaillierte Logs und Timing
- Cache aktivieren - Schema- und Query-Caching
- Cache-TTL - Standard: 5 Minuten, anpassbar
# Kurze API-URLs aktivieren
RewriteRule ^api/rexql/?$ index.php?rex-api-call=rexql [L,QSA]
RewriteRule ^api/rexql/proxy/?$ index.php?rex-api-call=proxy [L,QSA]
RewriteRule ^api/rexql/auth/?$ index.php?rex-api-call=auth [L,QSA]
Da v1.0 ein kompletter Rewrite ist, sind keine Migrations-Pfade verfügbar. Neu aufsetzen empfohlen.
- GraphQL Spezifikation: https://graphql.org/
- REDAXO Dokumentation: https://redaxo.org/doku/main
- YForm Addon: https://github.com/yakamara/redaxo_yform
- GitHub Issues: https://github.com/FriendsOfREDAXO/rexql
- REDAXO Slack: #addon-rexql
- REDAXO Community: https://redaxo.org/community/
MIT License - siehe LICENSE Datei
Entwickelt von Yves Torres für die REDAXO Community