Using Sulu CMS as a Headless CMS
Need headless capabilities and the features of a full content management system? Here are three ways to use Sulu CMS headlessly.
As the number of devices and endpoints for data grow, the idea of headless content management has gained traction. In this article I’ll show you three approaches you can take to use Sulu as a headless CMS. We’ve also released a bundle with headless capability — and we’d love to get your feedback.
What is a headless CMS?
A fully headless CMS doesn’t offer a rendering engine at all. Instead, it is a content repository that can only be accessed via API. It is then up to the developer to build a frontend to display the content, for example a JavaScript application using a framework like ReactJS or Angular.
Of course the type of frontend isn’t limited to a web browser: the point of headless architecture is to enable developers to build applications for smart watches, internet-connected fridges, car entertainment systems, and any device that the Internet of Things can dream up in the future.
The market is growing, with both open source and cloud-based SaaS services that offer headless-only content management. As well as that, existing CMSs are adapting by becoming decoupled.
A decoupled CMS makes it possible to access content directly via an API, but it also delivers HTML as usual using the rendering engine. This is the best of both worlds — headless capability with the benefits of a full CMS.
This is the approach we have chosen for Sulu: there are ways of using it in headless mode, but you can still use all the features the rendering engine provides, which is very convenient. While we see an increase in demand for headless applications, we don’t see any reason to discard the features of a full content management system because it deals with many complex tasks, such as the rendering engine, caching, image resizing and content previews.
Check out our article “Understanding the Pros and Cons of Headless Architecture to Unlock its Potential” in the IPC Whitepaper Selection 2020.
Why go headless?
An example of where we’ve used a headless approach is an intranet for a large international corporate client. They needed an event calendar with extensive custom business logic. It was a good fit for a headless implementation because it required content to be customized to employees according to many attributes such as their department, country, and job, which meant the content was dynamic and not easy to cache. This case illustrates the strength of using Sulu headlessly: unlike many stand-alone headless CMSs, you can use Symfony with Sulu to build intricate custom business logic.
Our philosophy when developing Sulu is to keep things as lightweight as possible, which we’re able to do because Symfony enables developers to add any non-standard functionality they need. However, as we hear from our community of developers that they implement some features time and time again, we can figure out when we need to build a standard solution. Headless architecture is one example: Sulu can be used in headless mode, but as more community members ask us about this, we’re developing an out-of-the-box solution.
There are currently three ways of using Sulu in headless mode, which I’m going to go through now.
How to use Sulu as a headless CMS
1. Write your own controllers
The most comprehensive solution at the moment is to write your own endpoints, but this is a lot of work. You will need to write the appropriate database queries to get the required data, and write custom controllers as well as serialize the data that is then passed on to the API.
This approach is the most flexible, allowing you to craft an API to your specific needs. It may also be the best option for larger, high-traffic projects because you can optimize performance by hand-writing your database queries. Once you’ve got the hang of it, you have a lot of flexibility because you can expose all your Symfony entities via API.
2. The Twig template method
The easiest way to get JSON data out of Sulu at the moment is to add the following to templates/pages/default.json.twig, as described by Sulu community member Giso Stallenberg:
You can then add the extension .json to a page in order to access the data in JSON format. Giso opened an issue calling for an improvement in headless support, where he documents the drawbacks of this approach. They include limitations in the data that can be displayed and non-availability of navigation items.
Nevertheless, this approach is appropriate for applications where you only need the data that is usually displayed on a page, or where you want to serve a page normally but make any further updates via an AJAX call. For example, a list of articles with a “load more” button to fetch more. It’s an easier approach, using only what’s built in and not adding any more dependencies to your Sulu install.
This approach is supported out-of-the-box since Sulu 1.6.
3. WIP: The SuluHeadlessBundle
Following on from Giso’s issue and discussions in our Slack community, we released the code we were developing to deliver headless projects with Sulu. SuluHeadlessBundle is now available as a bundle on GitHub. We’d love to hear your feedback.
The advantage of this approach is that you can expose more data for more complex use cases than is possible with the Twig-template approach, above. However, you should be aware that this bundle is a “working draft” — although we have used it in production, only advanced Sulu developers should do so themselves, and it might be worth getting in touch with us for professional support.
As pointed out by Sulu community member Jaap Romijn in our Slack channel, HTML post-processing (which we call markup parsing) doesn’t work with this method. Markup parsing is when Sulu parses the rendered markup and replaces parts of it. For an example, see the documentation on the sulu-link tag. Jaap’s suggested solution is to create serialization handlers/subscribers but we are still working on supporting this in HeadlessBundle.
We’re working to improve documentation too, but if you have any specific questions you can ask them in our Slack channel or open an issue on GitHub.
At least when it’s finished, the bundle will be easy to enable, and it’s tightly integrated into Sulu. We’re working on adding automatic serialization for all content types, as well as snippets. We have plans to build a new version of ContentBundle, which allows you to attach content to custom entities. Only custom entities that use ContentBundle can be exposed via HeadlessBundle. Please be aware that not all content types are supported at the moment: you can see the current status in this GitHub issue. (Those that are checked are currently supported.)
Long-term, once we’ve cleaned up the code, gathered feedback from the community, and tested it thoroughly, we would consider adding it to a future major Sulu version as a core feature.
Try it out and give us your feedback!
We can’t wait to hear back from the community about how SuluHeadlessBundle works for you. Let’s continue the conversation on the Slack channel and on GitHub!