[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"btz8hO-MXSFLpybqvfjYVBre4OvrEJO1wFySe3Zmv-s":3,"9_t0YFtO844PW3-iCfPxRTbw8yv0-2zzu2bChZFenjo":39,"msoRyzbqcDxj9uHXOwph75IB5iRNO2ERdPHOefcIpzU":75,"bQgCpskGRfkFm_sCgt_ntlND-r9IaTcRDV6kbNIgq28":190,"_apollo:default":232},{"menu":4},{"__typename":5,"id":6,"name":7,"items":8},"Menu","footer","Fußzeile",[9,24,29,34],{"__typename":10,"id":11,"title":12,"description":13,"url":14,"langcode":15,"internal":20,"expanded":21,"attributes":22},"MenuItem","e2873307-b50a-4aab-b6b2-1950fd99c72e","Impressum",null,"/impressum",{"__typename":16,"id":17,"name":18,"direction":19},"Language","de","German","ltr",true,false,{"__typename":23,"class":13},"MenuItemAttributes",{"__typename":10,"id":25,"title":26,"description":13,"url":27,"langcode":15,"internal":20,"expanded":21,"attributes":28},"2cd9b7c9-142a-4ea3-b898-a0952c54a195","Datenschutz","/datenschutz",{"__typename":23,"class":13},{"__typename":10,"id":30,"title":31,"description":13,"url":32,"langcode":15,"internal":20,"expanded":21,"attributes":33},"a5effba3-5a8c-4125-8d78-0cdba09824db","AGB","/agb",{"__typename":23,"class":13},{"__typename":10,"id":35,"title":36,"description":13,"url":37,"langcode":15,"internal":21,"expanded":21,"attributes":38},"114bf071-bdbb-44cf-85c1-69e9d9e0777d","Newsletter","https://liechtenecker.at/newsletter-subscribe",{"__typename":23,"class":13},{"menu":40},{"__typename":5,"id":41,"name":42,"items":43},"nuxt-main-menu","Nuxt Hauptmenü",[44,50,55,60,65,70],{"__typename":10,"id":45,"title":46,"description":13,"url":47,"langcode":48,"internal":20,"expanded":21,"attributes":49},"9ffc5019-cbd8-4b2e-8eb7-9feae486d4a1","Blog","/know-how",{"__typename":16,"id":17,"name":18,"direction":19},{"__typename":23,"class":13},{"__typename":10,"id":51,"title":52,"description":13,"url":53,"langcode":48,"internal":20,"expanded":21,"attributes":54},"1c7a5430-8a42-4b24-9544-252adabc2f4c","Projekte","/projekte",{"__typename":23,"class":13},{"__typename":10,"id":56,"title":57,"description":13,"url":58,"langcode":48,"internal":20,"expanded":21,"attributes":59},"9c4feedc-79e4-4fbf-b68c-065f33ebfe4c","Sparring","/workshop-ux-sparring-fuer-unternehmen",{"__typename":23,"class":13},{"__typename":10,"id":61,"title":62,"description":13,"url":63,"langcode":48,"internal":20,"expanded":21,"attributes":64},"3b77a27b-272a-489f-843e-53e23ed07741","Trainings","/liechtenecker-ux-academy",{"__typename":23,"class":13},{"__typename":10,"id":66,"title":67,"description":13,"url":68,"langcode":48,"internal":20,"expanded":21,"attributes":69},"ce0bb82b-e1ee-4036-be95-f693a62e9f4a","Über uns","/about",{"__typename":23,"class":13},{"__typename":10,"id":71,"title":72,"description":13,"url":73,"langcode":48,"internal":20,"expanded":21,"attributes":74},"04a19381-81a9-4694-8653-182d8855d2b5","Kontakt","/kontakt",{"__typename":23,"class":13},{"route":76},{"__typename":77,"entity":78},"RouteInternal",{"__typename":79,"id":80,"title":81,"changed":82,"created":88,"langcode":91,"path":92,"promote":21,"status":20,"sticky":21,"metatag":93,"postCategory":117,"postContentElements":13,"evergreen":13,"tags":142,"postWpBody":156,"wpHeaderImage":160,"wpHeaderImageOld":173,"wpHeaderImageOldSmall":13,"wpOgImage":174,"wpPromotedTeaserImage":13,"wpShareDescription":13,"wpShareTitle":13,"wpTeaserText":159,"wpYoastHead":183,"author":184},"NodeWpPost","745","Going Headless with Drupal",{"__typename":83,"timestamp":84,"timezone":85,"offset":86,"time":87},"DateTime",1670842520,"UTC","+00:00","2022-12-12T10:55:20+00:00",{"__typename":83,"timestamp":89,"timezone":85,"offset":86,"time":90},1669722363,"2022-11-29T11:46:03+00:00",{"__typename":16,"id":17,"name":18,"direction":19},"/blog/going-headless-with-drupal",[94,101,108,113],{"__typename":95,"tag":96,"attributes":97},"MetaTagValue","meta",{"__typename":98,"name":99,"content":100},"MetaTagValueAttributes","title","Going Headless with Drupal | Liechtenecker UX Design Studio",{"__typename":102,"tag":103,"attributes":104},"MetaTagLink","link",{"__typename":105,"href":106,"hreflang":13,"rel":107,"media":13,"sizes":13,"type":13},"MetaTagLinkAttributes","http://liechtenecker-cms.liechtenecker-cms.svc.cluster.local/blog/going-headless-with-drupal","canonical",{"__typename":109,"tag":96,"attributes":110},"MetaTagProperty",{"__typename":111,"property":112,"content":81},"MetaTagPropertyAttributes","og:title",{"__typename":109,"tag":96,"attributes":114},{"__typename":111,"property":115,"content":116},"og:image","http://liechtenecker-cms.liechtenecker-cms.svc.cluster.local/sites/default/files/styles/meta_og_image/public/wp-migration/wordpress-media-image/2022/11/BLOG_NS_forward_v02_SHARING-1204x630px_new.jpg?h=3ecc83bb&itok=iIfi89_j",{"__typename":118,"id":119,"name":120,"path":121,"status":20,"weight":122,"description":123,"langcode":127,"changed":128,"metatag":131},"TermCategories","7","Technologie","/kategorie/technologie",0,{"__typename":124,"processed":125,"format":126},"Text","Development Themen sowie zukünftige Technologien, mit denen wir uns auseinandersetzen. ","wp_html",{"__typename":16,"id":17,"name":18,"direction":19},{"__typename":83,"timestamp":129,"timezone":85,"offset":86,"time":130},1713772777,"2024-04-22T07:59:37+00:00",[132,135,139],{"__typename":95,"tag":96,"attributes":133},{"__typename":98,"name":99,"content":134},"Technologie | Liechtenecker UX Design Studio",{"__typename":95,"tag":96,"attributes":136},{"__typename":98,"name":137,"content":138},"description","Development Themen sowie zukünftige Technologien, mit denen wir uns auseinandersetzen.",{"__typename":102,"tag":103,"attributes":140},{"__typename":105,"href":141,"hreflang":13,"rel":107,"media":13,"sizes":13,"type":13},"http://liechtenecker-cms.liechtenecker-cms.svc.cluster.local/kategorie/technologie",[143,148,152],{"__typename":144,"id":145,"name":146,"path":147,"weight":122},"TermTags","235","CMS","/tag/cms",{"__typename":144,"id":149,"name":150,"path":151,"weight":122},"378","Druplal","/tag/druplal",{"__typename":144,"id":153,"name":154,"path":155,"weight":122},"1299","technologie","/tag/technologie",{"__typename":157,"processed":158,"format":126,"summary":159},"TextSummary","\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Wie in Fabians Blogbeitrag beschrieben wurde, geht es bei Headless CMS darum, Inhalte über eine Schnittstelle (Bsp.: \u003Ca href=\"https://de.wikipedia.org/wiki/Representational_State_Transfer\">REST\u003C/a>) in einem standardisierten Format bereitzustellen, damit diese von diversen Clients (Bsp.: Website Frontend, Native App, …) konsumiert werden können. Man kann natürlich so weit gehen, die Inhalte auch über die Schnittstelle zu verwalten, aber da Drupal bereits mit einigen Administration-Themes ausgeliefert wird und mit Contrib-Themes, wie dem \u003Ca href=\"https://www.drupal.org/project/gin\">Gin-Theme\u003C/a>, auch out-of-the-box gut zu bedienen ist, werden wir uns in diesem Beitrag nur auf das Bereitstellen von Inhalten beschränken.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Ch2>Drupal Core Module\u003C/h2>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Zu Beginn gleich eine gute Nachricht: Drupal 9 wird bereits mit allen notwendigen Modulen ausgeliefert, um REST APIs bereitzustellen! Im Folgenden werde ich kurz die Funktionalität der Module zusammenfassen.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Ch3>Serialization\u003C/h3>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Modul-URL: \u003Ca href=\"https://www.drupal.org/docs/8/core/modules/serialization\">https://www.drupal.org/docs/8/core/modules/serialization\u003C/a>\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Drupal verarbeitet Inhalte intern als Entities. Details zur Entity-API können auf der \u003Ca href=\"https://www.drupal.org/docs/drupal-apis/entity-api\">offiziellen Drupal Seite\u003C/a> nachgelesen werden. Für diesen Blogbeitrag ist nur wichtig zu verstehen, dass alle Entities für Drupal PHP-Objekte sind.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Um diese Objekte via HTTP(S) an Clients übertragen zu können, müssen sie in ein Format konvertiert werden, welches von den Clients gelesen werden kann. Hier kommt das \u003Cem>Serialization\u003C/em>-Modul ins Spiel. Es stellt ein Service bereit, welches Daten (wie unser Entity-Objekt) in Formate wie \u003Ca href=\"https://de.wikipedia.org/wiki/JavaScript_Object_Notation\">JSON\u003C/a> oder \u003Ca href=\"https://de.wikipedia.org/wiki/Extensible_Markup_Language\">XML\u003C/a> serialisiert. Zusätzlich kann das Service natürlich auch den umgekehrten Weg gehen: also Daten, welche in Formaten wie JSON oder XML vorliegen, in PHP-Objekte zu deserialisieren.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>In der \u003Ca href=\"https://www.drupal.org/docs/drupal-apis/serialization-api\">Dokumentation der Serialization-API\u003C/a> kann man nachlesen, wie das Serialisieren/Deserialisieren technisch implementiert ist, wie man neue Formate (Bsp.: CSV) hinzufügen kann und wie die Funktionalität bereits existierende Serializer ändern kann.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Als gängiges Format für die Kommunikation in REST-APIs hat sich über die Zeit JSON etabliert. Daher wird dieses Format standardmäßig vom \u003Cem>Serialization\u003C/em>-Modul unterstützt.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Das \u003Cem>Serialization\u003C/em>-Modul wird von allen weiteren Modulen zum Serialisieren/Deserialisieren von Daten verwendet.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Ch3>RESTful Web Services\u003C/h3>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Modul-URL: \u003Ca href=\"https://www.drupal.org/docs/8/core/modules/rest\">https://www.drupal.org/docs/8/core/modules/rest\u003C/a>\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Dieses Modul kann sowohl \u003Ca href=\"https://www.drupal.org/docs/8/core/modules/rest/2-get-for-reading-content-entities\">Entitäten\u003C/a> als auch \u003Ca href=\"https://www.drupal.org/docs/drupal-apis/restful-web-services-api/custom-rest-resources\">benutzerdefinierte Ressourcen\u003C/a> via REST API bereitstellen. Da man beim Implementieren von Custom REST-Ressourcen weder beim Aufbau der URL noch bei der Struktur des Request-Bodies beschränkt ist, kann man alle möglichen komplexen Business-Cases implementieren. Hier sind der Komplexität und Kreativität keine Grenzen gesetzt.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>\u003Cstrong>Note:\u003C/strong> Wie in der \u003Ca href=\"https://www.drupal.org/docs/drupal-apis/restful-web-services-api/restful-web-services-api-overview#s-api-features\">Dokumentation gut beschrieben ist\u003C/a>, muss jedes \u003Cem>RestResource\u003C/em>-Plugin, welches man für die REST-API freischalten möchte, eine entsprechende Config-Entity angelegt werden. Mithilfe des Contrib-Moduls \u003Ca href=\"https://www.drupal.org/project/restui\">REST UI\u003C/a>, kann dieser Schritt bequem im User Interface durchgeführt werden. Das erleichtert die Arbeit um ein Vielfaches! 😉\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Ch3>JSON:API\u003C/h3>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Das \u003Cem>JSON:API\u003C/em> Modul implementiert die \u003Ca href=\"https://jsonapi.org/\">JSON:API Spezifikation\u003C/a> für Drupal Entities. Im Gegensatz zum \u003Cem>RESTful Web Services\u003C/em>-Modul stellt das \u003Cem>JSON:API\u003C/em>-Modul auch Collection-Ressourcen bereit. Beim Laden der Entity-Listen bietet es eine Vielzahl von Funktionen, wie das \u003Ca href=\"https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/filtering\">Filtern von Inhalten\u003C/a>, das Laden und \u003Ca href=\"https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/includes\">Inkludieren von Relations\u003C/a>, \u003Ca href=\"https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/sorting\">benutzerdefinierte Sortierung\u003C/a> und \u003Ca href=\"https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/pagination\">Paginierung\u003C/a>.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Zu beachten ist jedoch, dass das Core-Modul \u003Cstrong>keine Konfigurationsmöglichkeiten\u003C/strong> bietet und somit \u003Cstrong>alle Entity-Typen\u003C/strong> via REST-API bereitstellt! Das ist in den meisten Fällen nicht notwendig und auch nicht erwünscht. Glücklicherweise gibt es für diesen Fall ein Contrib-Modul namens \u003Ca href=\"https://www.drupal.org/project/jsonapi_extras\">\u003Cem>JSON:API Extras\u003C/em>\u003C/a>, das die Konfiguration einzelner Ressourcen erlaubt. Damit kann man einzelne Entity-Typen und Bundles für die REST API freigeben.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Ch3>Anmerkung zur Datensicherheit\u003C/h3>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Als Sicherheitsaspekt sei noch erwähnt, dass beide Module Drupals Entity-Access respektieren. Also unabhängig, ob man Entities über das \u003Cem>RESTful Web Services\u003C/em>-Modul oder das \u003Cem>JSON:API\u003C/em>-Modul bereitstellt, werden Inhalte, auf die ein Benutzer keinen Zugriff hat, nicht an den Verbraucher ausgeliefert.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Ch3>Das Headless Setup bei Liechtenecker\u003C/h3>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Da das \u003Cem>JSON:API\u003C/em>-Modul out-of-the-box mehr Funktionen als die Entity-Ressource des \u003Cem>RESTful Web Services\u003C/em>-Modul bietet, verwenden wir das \u003Cem>JSON:API\u003C/em>-Modul zum Bereitstellen von Entities. In der Dokumentation des Moduls gibt es eine \u003Ca href=\"https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/jsonapi-vs-cores-rest-module\">Tabelle\u003C/a>, welche die Unterschiede zwischen dem \u003Cem>JSON:API\u003C/em>– und dem \u003Cem>RESTful Web Services\u003C/em>-Modul übersichtlich darstellt.&nbsp;\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Wenn wir für Spezialfälle komplexe Abfragen oder Workflows benötigen, welche den Funktionsumfang von \u003Cem>JSON:API\u003C/em> sprengen, implementieren wir dafür custom \u003Cem>RestResource\u003C/em>-Plugins, die dann vom \u003Cem>RESTful Web Services\u003C/em>-Modul via REST-API bereitgestellt werden.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Ch3>Challenges\u003C/h3>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>So toll das auch klingt, es gab immer noch einige Herausforderungen zu bewältigen, bevor wir Drupal als vollwertiges Headless CMS akzeptiert haben. Im Folgenden werde ich kurz auf die größten eingehen, die uns bei der Implementierung aufgefallen sind und kurz umreißen, wie wir die Probleme gelöst haben.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Ch4>Routing/Path aliases\u003C/h4>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Die systeminternen URLs zu Inhalten sind in Drupal nicht sonderlich schön. Die URLs werden gewöhnlich aus der Entity-Type-ID und der Entity-ID zusammengebaut. Also sieht die URL eines Blogposts beispielsweise so aus: /node/3927.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>node ist dabei die Entity-Type-ID und 3927 die Entity-ID.&nbsp;\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Da man keinen SEO-Experten auf dieser Welt finden wird, der mit dieser URL Struktur zufrieden ist, wird Drupal mit einem Modul namens \u003Ca href=\"https://www.drupal.org/docs/8/core/modules/path/overview\">\u003Cem>Path\u003C/em>\u003C/a> ausgeliefert. Mit diesem kann man für jede Inhalts-Seite einen URL-Alias definieren, welcher dann wiederum von dem Modul auf die jeweilige interne URL auflöst. Das \u003Cem>Path\u003C/em>-Modul funktioniert allerdings nur in einem monolithischen Kontext, da das \u003Cem>JSON:API\u003C/em>-Modul eigene Routes zum Laden von Entities via REST-API bereitstellt.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Die internen \u003Cem>JSON:API\u003C/em> Routes haben folgende Struktur:\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>/jsonapi/&lt;entity-type&gt;/&lt;bundle&gt;/&lt;entity-uuid&gt;\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Als Beispiel für einen Blogpost also:\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>/jsonapi/node/blogpost/1a7cb8d0-3210-43dd-802b-2003b3c81ace\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Man stelle sich nun vor, ein Benutzer öffnet den Browser und besucht folgende URL:\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>\u003Ca href=\"/blog/going-headless-with-drupal\">https://legacy.liechtenecker.dev/blog/going-headless-with-drupal\u003C/a>\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Wir gehen hier von einem Decoupled-Kontext aus, daher löst die Domain liechtenecker.at auf unsere Frontend-Web-App (\u003Ca href=\"https://v3.nuxtjs.org/\">Nuxt\u003C/a>) auf, welche als Datenquelle die Drupal-REST-API verwendet. Sofern nicht alle verfügbaren Seiten in Nuxt pre-rendered vorliegen, kennt das Frontend nicht alle im CMS verfügbaren URLs — vor allem nicht die Drupal-internen mit den Entity-UUIDs, die zum Laden von \u003Cem>JSON:API\u003C/em>-Ressourcen benötigt werden.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Wir brauchen also die Möglichkeit, \u003Cem>JSON:API\u003C/em>-Ressourcen via Path-Alias zu laden:\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>GET /jsonapi/blog/going-headless-with-drupal\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Dafür habe ich mir angeschaut, wie das \u003Cem>Path\u003C/em>-Modul diese Aufgabe löst: dort prüft ein \u003Ca href=\"https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21PathProcessor%21InboundPathProcessorInterface.php/interface/InboundPathProcessorInterface\">Inbound-Path-Processor\u003C/a>, ob die aktuelle URL ein registrierter Alias ist — wenn dem so ist, wandelt der Processor den Alias auf den internen Pfad um, der dann vom Routing-System verarbeitet werden kann.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Da dachte ich mir: cool gelöst! Exakt denselben Schmäh können wir auch für unsere /jsonapi/ URLs implementieren! Gesagt, getan: so kam es, dass wir einen Inbound Path Processor implementiert haben, welcher alle&nbsp; eingehenden URLs auf /jsonapi/&lt;diverse-strings-und-subpaths&gt; analysiert und prüft, ob &lt;diverse-strings-und-subpaths&gt; ein registrierter Path-Alias ist. Sofern ein Alias gefunden wurde, wandelt der Path-Processor den Alias in den Drupal-internen \u003Cem>JSON:API\u003C/em>-Pfad um, der dann von Drupals Routing-System verarbeitet werden kann → solved ✅\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Ch3>Previews\u003C/h3>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Als Content-Manager hat man bei großen Änderungen oft das Bedürfnis, Inhalte vor der Veröffentlichung zu reviewen. In einem decoupled Szenario ist das nicht so einfach umzusetzen, da die Inhalte ja eigentlich nicht gespeichert werden sollten, bevor das OK vom Reviewer gegeben wurde. Das Problematische an der Sache ist, dass es nicht möglich ist, nicht gespeicherte Inhalte über eine REST-API bereitzustellen — ein Dilemma!\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Um das Problem zu umgehen, nutzen wir Drupals built-in Content-Versioning-System in Kombination mit dem \u003Ca href=\"https://www.drupal.org/docs/8/core/modules/content-moderation/overview\">\u003Cem>Content Moderation\u003C/em>-Modul\u003C/a>. Dieses erlaubt es neue Revisionen von Inhalten zu erstellen, welche nicht gleich veröffentlicht werden, sondern erstmal als “Draft” vorliegen, während die bereits veröffentlichte Version davon unverändert bleibt! Erst wenn der neuere Draft vom Editor veröffentlicht wird, werden die Änderungen für End User sichtbar.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Des Weiteren nutzen wir die Funktion des \u003Cem>JSON:API\u003C/em>-Moduls, Inhalte in bestimmten Versionen mittels\u003Ca href=\"https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/revisions\"> resourceVersion Parameter \u003C/a>zu laden.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Hier ist noch folgendes zu beachten: der User, der die Preview-Seite aufruft, benötigt die entsprechenden Berechtigungen um auf unveröffentlichte Revisionen der Inhalte zugreifen zu dürfen (der Draft ist ja nicht veröffentlicht)! Das kann unterschiedlich gelöst werden:\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3  standard-list\">\n            \n\u003Col>\u003Cli>Um die Previews im Frontend aufzurufen, muss man auch im Frontend authentifiziert sein.\u003C/li>\u003Cli>Man generiert im CMS einen kurzlebigen previewToken und gewährt Benutzern mit gültigen previewToken programmatisch lesenden Zugriff auf die Inhalte.\u003C/li>\u003C/ol>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Diese Optionen müssen pro Projekt abgewogen und entschieden werden.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Um Previews für Content-Editoren so angenehm wie möglich zu gestalten, haben wir die Funktionalität des Preview-Buttons bei Inhalten angepasst, dass beim Klick darauf folgendes passiert \u003Cem>(bei Option a ohne \u003C/em>\u003Cem>previewToken\u003C/em>\u003Cem>)\u003C/em>:\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3  standard-list\">\n            \n\u003Cul>\u003Cli>Alle Änderungen werden als neue Revision im Status “draft” gespeichert. Die neue Revisions-ID wird dann beim Generieren der Preview-URL verwendet.\u003C/li>\u003Cli>\u003Cem>(nur bei Option b)\u003C/em> Das CMS generiert einen temporären Preview-Token, der später für die Zugriffskontrolle von unveröffentlichten Inhalts-Revisionen dient.\u003C/li>\u003Cli>Das CMS generiert die Frontend-Preview-URL:\u003Cbr>https://&lt;frontend-base-url&gt;/&lt;path-alias&gt;?previewToken=&lt;previewToken&gt;&amp;resourceVersion=&lt;revisionID&gt;\u003C/li>\u003Cli>Das CMS öffnet einen neuen Tab mit der Frontend-Preview-URL.\u003C/li>\u003Cli>Die Frontend-Web-App versucht den Inhalt für den Pfad &lt;path-alias&gt; dynamisch aus der CMS-REST-API zu laden und übergibt dabei den previewToken und resourceVersion Parameter:\u003Cbr>https://&lt;cms-api-base-url&gt;/jsonapi/&lt;path-alias&gt;?previewToken=&lt;previewToken&gt;&amp;resourceVersion=&lt;revisionID&gt;\u003C/li>\u003Cli>Da das \u003Cem>JSON:API\u003C/em>-Modul out-of-the-box das Laden von spezifischen Revisions unterstützt, wird automatisch die korrekte Version zurückgegeben!\u003C/li>\u003C/ul>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>→ solved ✅\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Ch2>Conclusion\u003C/h2>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Zusammenfassend kann man sagen, dass \u003Cem>Drupal Core\u003C/em> bereits mit den wichtigsten Features für ein Headless CMS ausgeliefert wird. Trotz der Challenges, die beim initialen Einrichten für etwas Kopfzerbrechen gesorgt haben, sind wir überzeugt davon, dass wir mit Drupal auf ein zukunftssicheres erweiterbares System setzen. Da wir die größten Challenges bereits gelöst haben, ist das Setup von neuen Headless-Projekten nun rasch erledigt, wodurch wir uns auch mit Drupal direkt auf das Modellieren der Daten konzentrieren können.\u003Cbr>Beim Vergleich mit anderen Node-JS-basierten Systemen gewinnt Drupal in Punkten Dokumentation und Erweiterbarkeit. Was uns auch an den sonst weit verbreiteten Headless CMS stört, ist, dass es bei den meisten keine Möglichkeit des Self-Hostings mehr gibt.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Ein weiterer großer Pluspunkt von Drupal als CMS (sei es nun Headless oder monolitisch) ist die sehr engagierte Open-Source Community. Auf \u003Ca href=\"https://drupal.org\">https://drupal.org\u003C/a> werden Issues auf sehr hohem Niveau diskutiert, Neuentwicklungen im Core werden mit großartig kritischen Augen betrachtet und es wird hoher Wert auf automatisiert abgetesteten Code gelegt.\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n\n\n\n\u003Cdiv class=\"grid-wrapper\">\n    \u003Cdiv class=\"row\">\n        \u003Cdiv class=\"default-left col-xsmall-12 col-medium-6 col-medium-offset-2 col-large-6 col-large-offset-3 \">\n            \n\u003Cp>Gibt es Fragen oder Anmerkungen? Schreibt uns gerne in die Kommentare!\u003C/p>\n        \u003C/div>\n    \u003C/div>\n\u003C/div>\n\n","Vor einiger Zeit hat sich mein Kollege Fabian in einem Blogpost mit dem Thema Headless CMS befasst. Darauf ausgehend möchte ich heute auf Drupal als Headless CMS eingehen und aufzeigen was gut läuft und über welche Hürden man dabei stößt. ",{"__typename":161,"id":162,"excludeFromScreenreader":13,"mediaImage":163,"name":169,"path":172,"status":20},"MediaImage","441",{"__typename":164,"url":165,"width":166,"height":167,"alt":168,"title":169,"size":170,"mime":171},"Image","http://liechtenecker-cms.liechtenecker-cms.svc.cluster.local/sites/default/files/wp-migration/wordpress-media-image/2022/11/BLOG_LK_GoingHeadless_Drupal_TITEL-2880x1300px_new-scaled.jpg",2560,1156,"Headless CMS Drupal","BLOG_LK_GoingHeadless_Drupal_TITEL-2880x1300px_new",450641,"image/jpeg","/media/441/edit",{"__typename":161,"id":162,"excludeFromScreenreader":13,"mediaImage":163,"name":169,"path":172,"status":20},{"__typename":161,"id":175,"excludeFromScreenreader":13,"mediaImage":176,"name":180,"path":182,"status":20},"440",{"__typename":164,"url":177,"width":178,"height":179,"alt":168,"title":180,"size":181,"mime":171},"http://liechtenecker-cms.liechtenecker-cms.svc.cluster.local/sites/default/files/wp-migration/wordpress-media-image/2022/11/BLOG_NS_forward_v02_SHARING-1204x630px_new.jpg",1204,630,"BLOG_NS_forward_v02_SHARING-1204x630px_new",429843,"/media/440/edit","\u003C!-- This site is optimized with the Yoast SEO plugin v15.7 - https://yoast.com/wordpress/plugins/seo/ -->\n\u003Cmeta name=\"description\" content=\"In unserem aktuellen Blogpost geben wir einen Einblick was Drupal Core alles mit sich bringt um es als Headless CMS zu verwenden. Auf welche Challenges wir dabei gestossen sind und wie wir diese gelöst haben könnt ihr hier nachlesen.\" />\n\u003Cmeta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" />\n\u003Clink rel=\"canonical\" href=\"https://legacy.liechtenecker.dev/blog/going-headless-with-drupal/\" />\n\u003Cmeta property=\"og:locale\" content=\"de_DE\" />\n\u003Cmeta property=\"og:type\" content=\"article\" />\n\u003Cmeta property=\"og:title\" content=\"Going Headless with Drupal - Liechtenecker Blogpost\" />\n\u003Cmeta property=\"og:description\" content=\"In unserem aktuellen Blogpost geben wir einen Einblick was Drupal Core alles mit sich bringt um es als Headless CMS zu verwenden. Auf welche Challenges wir dabei gestossen sind und wie wir diese gelöst haben könnt ihr hier nachlesen.\" />\n\u003Cmeta property=\"og:url\" content=\"https://legacy.liechtenecker.dev/blog/going-headless-with-drupal/\" />\n\u003Cmeta property=\"og:site_name\" content=\"Liechtenecker\" />\n\u003Cmeta property=\"article:published_time\" content=\"2022-11-29T12:46:03+00:00\" />\n\u003Cmeta property=\"article:modified_time\" content=\"2022-12-12T11:55:20+00:00\" />\n\u003Cmeta name=\"twitter:card\" content=\"summary_large_image\" />\n\u003Cmeta name=\"twitter:label1\" content=\"Geschätzte Lesezeit\">\n\t\u003Cmeta name=\"twitter:data1\" content=\"7 Minuten\">\n\u003Cscript type=\"application/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"WebSite\",\"@id\":\"https://legacy.liechtenecker.dev/#website\",\"url\":\"https://legacy.liechtenecker.dev/\",\"name\":\"Liechtenecker\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"https://legacy.liechtenecker.dev/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"de-DE\"},{\"@type\":\"WebPage\",\"@id\":\"https://legacy.liechtenecker.dev/blog/going-headless-with-drupal/#webpage\",\"url\":\"https://legacy.liechtenecker.dev/blog/going-headless-with-drupal/\",\"name\":\"Going Headless with Drupal - Liechtenecker Blogpost\",\"isPartOf\":{\"@id\":\"https://legacy.liechtenecker.dev/#website\"},\"datePublished\":\"2022-11-29T12:46:03+00:00\",\"dateModified\":\"2022-12-12T11:55:20+00:00\",\"author\":{\"@id\":\"https://legacy.liechtenecker.dev/#/schema/person/d8b80cc046b867225321ea8b7a2a6de7\"},\"description\":\"In unserem aktuellen Blogpost geben wir einen Einblick was Drupal Core alles mit sich bringt um es als Headless CMS zu verwenden. Auf welche Challenges wir dabei gestossen sind und wie wir diese gel\\u00f6st haben k\\u00f6nnt ihr hier nachlesen.\",\"inLanguage\":\"de-DE\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https://legacy.liechtenecker.dev/blog/going-headless-with-drupal/\"]}]},{\"@type\":\"Person\",\"@id\":\"https://legacy.liechtenecker.dev/#/schema/person/d8b80cc046b867225321ea8b7a2a6de7\",\"name\":\"Daniel\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https://legacy.liechtenecker.dev/#personlogo\",\"inLanguage\":\"de-DE\",\"url\":\"https://secure.gravatar.com/avatar/5708f7599c8e99528411ef29bef1ee34?s=96&d=mm&r=g\",\"caption\":\"Daniel\"}}]}\u003C/script>\n\u003C!-- / Yoast SEO plugin. -->",{"__typename":185,"id":186,"myRole":187,"name":188,"nickname":189},"User","5","Backend Development🤓","d-steindl","Daniel",{"latestKnowhow":191},[192,207,220],{"__typename":79,"id":193,"title":194,"path":195,"wpTeaserText":196,"wpPromotedTeaserImage":13,"wpHeaderImage":197},"1619","Behind the scenes: Ein Barrierefreiheits-Audit","/blog/behind-scenes-ein-barrierefreiheits-audit","”Entspricht unsere Website den gesetzlichen Anforderungen und wenn nicht, was genau müssen wir ändern?”\r\nDiese Frage lieben wir. Echt! Und so sieht unsere Antwort aus.",{"__typename":161,"id":198,"excludeFromScreenreader":13,"mediaImage":199,"name":205,"path":206,"status":20},"3364",{"__typename":164,"url":200,"width":201,"height":202,"alt":203,"title":13,"size":204,"mime":171},"http://liechtenecker-cms.liechtenecker-cms.svc.cluster.local/sites/default/files/2026-04/Headerbilder%20Blogartikel%20Behind%20the%20scene%20Accessibility%20Audit.jpg",2880,1300,"Headline mit Sujet: Tastatur mit Symbolen für Barrierefreiheit im Fokus auf hellem  Hintergrund",838204,"Headerbilder Blogartikel Behind the scene Accessibility Audit.jpg","/media/3364/edit",{"__typename":79,"id":208,"title":209,"path":210,"wpTeaserText":211,"wpPromotedTeaserImage":13,"wpHeaderImage":212},"1616","Agentic KI trifft Design-System: Wie unser Presentation Maker entstand.","/blog/agentic-ki-trifft-design-system-wie-unser-presentation-maker-entstand","Nein, wir wollen euch jetzt nicht erzählen, was KI alles kann. Aber wir möchten euch zeigen, wie wir mit KI umgehen. \r\n",{"__typename":161,"id":213,"excludeFromScreenreader":13,"mediaImage":214,"name":218,"path":219,"status":20},"3355",{"__typename":164,"url":215,"width":201,"height":202,"alt":216,"title":13,"size":217,"mime":171},"http://liechtenecker-cms.liechtenecker-cms.svc.cluster.local/sites/default/files/2026-03/BLOG_Presentation%20Tool_TITEL-2880x1300px_1.jpg","Lukas und Daniel  arbeiten an Computern im Büro.",2621988,"BLOG_Presentation Tool_TITEL-2880x1300px.jpg","/media/3355/edit",{"__typename":79,"id":221,"title":222,"path":223,"wpTeaserText":13,"wpPromotedTeaserImage":13,"wpHeaderImage":224},"1606","UI Trends 2026","/blog/ui-trends-2026",{"__typename":161,"id":225,"excludeFromScreenreader":21,"mediaImage":226,"name":230,"path":231,"status":20},"3303",{"__typename":164,"url":227,"width":201,"height":202,"alt":228,"title":13,"size":229,"mime":171},"http://liechtenecker-cms.liechtenecker-cms.svc.cluster.local/sites/default/files/2026-01/BLOG_Trendbericht%202026.jpg","UI Trends 2026, gelber Hintergrund, schwarze Schrift.",4700748,"BLOG_Trendbericht 2026.jpg","/media/3303/edit",{"Language:de":233,"MenuItem:e2873307-b50a-4aab-b6b2-1950fd99c72e":234,"MenuItem:2cd9b7c9-142a-4ea3-b898-a0952c54a195":238,"MenuItem:a5effba3-5a8c-4125-8d78-0cdba09824db":241,"MenuItem:114bf071-bdbb-44cf-85c1-69e9d9e0777d":244,"Menu:footer":247,"ROOT_QUERY":257,"MenuItem:9ffc5019-cbd8-4b2e-8eb7-9feae486d4a1":273,"MenuItem:1c7a5430-8a42-4b24-9544-252adabc2f4c":276,"MenuItem:9c4feedc-79e4-4fbf-b68c-065f33ebfe4c":279,"MenuItem:3b77a27b-272a-489f-843e-53e23ed07741":282,"MenuItem:ce0bb82b-e1ee-4036-be95-f693a62e9f4a":285,"MenuItem:04a19381-81a9-4694-8653-182d8855d2b5":288,"Menu:nuxt-main-menu":291,"TermCategories:7":305,"TermTags:235":316,"TermTags:378":317,"TermTags:1299":318,"MediaImage:441":319,"MediaImage:440":321,"User:5":323,"NodeWpPost:745":324,"MediaImage:3364":354,"NodeWpPost:1619":356,"MediaImage:3355":359,"NodeWpPost:1616":361,"MediaImage:3303":364,"NodeWpPost:1606":366},["null","__typename",16,"id",17,"name",18,"direction",19],["null","__typename",10,"id",11,"title",12,"description",13,"url",14,"langcode",235,"internal",20,"expanded",21,"attributes",237],{"__ref":236},"Language:de",["null","__typename",23,"class",13],["null","__typename",10,"id",25,"title",26,"description",13,"url",27,"langcode",239,"internal",20,"expanded",21,"attributes",240],{"__ref":236},["null","__typename",23,"class",13],["null","__typename",10,"id",30,"title",31,"description",13,"url",32,"langcode",242,"internal",20,"expanded",21,"attributes",243],{"__ref":236},["null","__typename",23,"class",13],["null","__typename",10,"id",35,"title",36,"description",13,"url",37,"langcode",245,"internal",21,"expanded",21,"attributes",246],{"__ref":236},["null","__typename",23,"class",13],["null","__typename",5,"id",6,"name",7,"items",248],[249,251,253,255],{"__ref":250},"MenuItem:e2873307-b50a-4aab-b6b2-1950fd99c72e",{"__ref":252},"MenuItem:2cd9b7c9-142a-4ea3-b898-a0952c54a195",{"__ref":254},"MenuItem:a5effba3-5a8c-4125-8d78-0cdba09824db",{"__ref":256},"MenuItem:114bf071-bdbb-44cf-85c1-69e9d9e0777d",["null","__typename",258,"menu({\"name\":\"FOOTER\"})",259,"menu({\"name\":\"NUXT_MAIN_MENU\"})",261,"route({\"path\":\"/blog/going-headless-with-drupal\"})",263,"latestKnowhow({\"excludeId\":\"745\",\"limit\":3})",266],"Query",{"__ref":260},"Menu:footer",{"__ref":262},"Menu:nuxt-main-menu",["null","__typename",77,"entity",264],{"__ref":265},"NodeWpPost:745",[267,269,271],{"__ref":268},"NodeWpPost:1619",{"__ref":270},"NodeWpPost:1616",{"__ref":272},"NodeWpPost:1606",["null","__typename",10,"id",45,"title",46,"description",13,"url",47,"langcode",274,"internal",20,"expanded",21,"attributes",275],{"__ref":236},["null","__typename",23,"class",13],["null","__typename",10,"id",51,"title",52,"description",13,"url",53,"langcode",277,"internal",20,"expanded",21,"attributes",278],{"__ref":236},["null","__typename",23,"class",13],["null","__typename",10,"id",56,"title",57,"description",13,"url",58,"langcode",280,"internal",20,"expanded",21,"attributes",281],{"__ref":236},["null","__typename",23,"class",13],["null","__typename",10,"id",61,"title",62,"description",13,"url",63,"langcode",283,"internal",20,"expanded",21,"attributes",284],{"__ref":236},["null","__typename",23,"class",13],["null","__typename",10,"id",66,"title",67,"description",13,"url",68,"langcode",286,"internal",20,"expanded",21,"attributes",287],{"__ref":236},["null","__typename",23,"class",13],["null","__typename",10,"id",71,"title",72,"description",13,"url",73,"langcode",289,"internal",20,"expanded",21,"attributes",290],{"__ref":236},["null","__typename",23,"class",13],["null","__typename",5,"id",41,"name",42,"items",292],[293,295,297,299,301,303],{"__ref":294},"MenuItem:9ffc5019-cbd8-4b2e-8eb7-9feae486d4a1",{"__ref":296},"MenuItem:1c7a5430-8a42-4b24-9544-252adabc2f4c",{"__ref":298},"MenuItem:9c4feedc-79e4-4fbf-b68c-065f33ebfe4c",{"__ref":300},"MenuItem:3b77a27b-272a-489f-843e-53e23ed07741",{"__ref":302},"MenuItem:ce0bb82b-e1ee-4036-be95-f693a62e9f4a",{"__ref":304},"MenuItem:04a19381-81a9-4694-8653-182d8855d2b5",["null","__typename",118,"id",119,"name",120,"path",121,"status",20,"weight",122,"description",306,"langcode",307,"changed",308,"metatag",309],["null","__typename",124,"processed",125,"format",126],{"__ref":236},["null","__typename",83,"timestamp",129,"timezone",85,"offset",86,"time",130],[310,312,314],["null","__typename",95,"tag",96,"attributes",311],["null","__typename",98,"name",99,"content",134],["null","__typename",95,"tag",96,"attributes",313],["null","__typename",98,"name",137,"content",138],["null","__typename",102,"tag",103,"attributes",315],["null","__typename",105,"href",141,"hreflang",13,"rel",107,"media",13,"sizes",13,"type",13],["null","__typename",144,"id",145,"name",146,"path",147,"weight",122],["null","__typename",144,"id",149,"name",150,"path",151,"weight",122],["null","__typename",144,"id",153,"name",154,"path",155,"weight",122],["null","__typename",161,"id",162,"excludeFromScreenreader",13,"mediaImage",320,"name",169,"path",172,"status",20],["null","__typename",164,"url",165,"width",166,"height",167,"alt",168,"title",169,"size",170,"mime",171],["null","__typename",161,"id",175,"excludeFromScreenreader",13,"mediaImage",322,"name",180,"path",182,"status",20],["null","__typename",164,"url",177,"width",178,"height",179,"alt",168,"title",180,"size",181,"mime",171],["null","__typename",185,"id",186,"myRole",187,"name",188,"nickname",189],["null","__typename",79,"id",80,"title",81,"changed",325,"created",326,"langcode",327,"path",92,"promote",21,"status",20,"sticky",21,"metatag",328,"category",337,"contentElements",13,"evergreen",13,"tags",339,"wpBody",346,"wpHeaderImage",347,"wpHeaderImageOld",349,"wpHeaderImageOldSmall",13,"wpOgImage",350,"wpPromotedTeaserImage",13,"wpShareDescription",13,"wpShareTitle",13,"wpTeaserText",159,"wpYoastHead",183,"author",352],["null","__typename",83,"timestamp",84,"timezone",85,"offset",86,"time",87],["null","__typename",83,"timestamp",89,"timezone",85,"offset",86,"time",90],{"__ref":236},[329,331,333,335],["null","__typename",95,"tag",96,"attributes",330],["null","__typename",98,"name",99,"content",100],["null","__typename",102,"tag",103,"attributes",332],["null","__typename",105,"href",106,"hreflang",13,"rel",107,"media",13,"sizes",13,"type",13],["null","__typename",109,"tag",96,"attributes",334],["null","__typename",111,"property",112,"content",81],["null","__typename",109,"tag",96,"attributes",336],["null","__typename",111,"property",115,"content",116],{"__ref":338},"TermCategories:7",[340,342,344],{"__ref":341},"TermTags:235",{"__ref":343},"TermTags:378",{"__ref":345},"TermTags:1299",["null","__typename",157,"processed",158,"format",126,"summary",159],{"__ref":348},"MediaImage:441",{"__ref":348},{"__ref":351},"MediaImage:440",{"__ref":353},"User:5",["null","__typename",161,"id",198,"excludeFromScreenreader",13,"mediaImage",355,"name",205,"path",206,"status",20],["null","__typename",164,"url",200,"width",201,"height",202,"alt",203,"title",13,"size",204,"mime",171],["null","__typename",79,"id",193,"title",194,"path",195,"wpTeaserText",196,"wpPromotedTeaserImage",13,"wpHeaderImage",357],{"__ref":358},"MediaImage:3364",["null","__typename",161,"id",213,"excludeFromScreenreader",13,"mediaImage",360,"name",218,"path",219,"status",20],["null","__typename",164,"url",215,"width",201,"height",202,"alt",216,"title",13,"size",217,"mime",171],["null","__typename",79,"id",208,"title",209,"path",210,"wpTeaserText",211,"wpPromotedTeaserImage",13,"wpHeaderImage",362],{"__ref":363},"MediaImage:3355",["null","__typename",161,"id",225,"excludeFromScreenreader",21,"mediaImage",365,"name",230,"path",231,"status",20],["null","__typename",164,"url",227,"width",201,"height",202,"alt",228,"title",13,"size",229,"mime",171],["null","__typename",79,"id",221,"title",222,"path",223,"wpTeaserText",13,"wpPromotedTeaserImage",13,"wpHeaderImage",367],{"__ref":368},"MediaImage:3303"]