When it comes to content management systems, Drupal is one of the key players in town and is a great example of a multi-purpose system with a very extensive set of features and capabilities, including a headless interface.
A Headless CMS, whether it’s Drupal, WordPress or any other, is a CMS that provides you with a different way of interacting with it: through an API.
With that being said, Drupal offers a couple of different flavors of headless that you can aim for, depending on your needs:
The classic headless architecture consists of Drupal as the back-end service, which provides all main CMS-related functionalities and storage (mainly of your content), while your front-end lives as a separate project, one with its own back-end using Drupal as an external, 3rd party service.
The architecture would look something like this:
In this scenario, you gain full control over the presentation of your site and you have the freedom to create any type of application.
With the classic setup, you could be developing a mobile native app, a desktop application or anything else with the capability of requesting and sending information to and from an external resource (in this case: Drupal).
While the previous example is perfect for someone looking for flexibility and trying to decouple their development from Drupal, you might not be looking for such a thing. Maybe you’re just trying to build a website on top of Drupal but the UI is just not what you want or perhaps what you’re trying to do is just a simple static site powered by Drupal but with a very customized presentation.
If this is you, then maybe you’d benefit from a simpler architecture, such as using JAMStack with a Drupal backend.
The above image shows what a Drupal-based JAMStack would look like.
If you’re not familiar with this technology stack, JAM stands for JavaScript, API and Markup. And it’s intended for scenarios like this one: when your back-end is completely dependent on a 3rd party API, in this case, Drupal.
In addition, JAMStack is also perfect for static sites, because their own intention is to display content, so all you need to do is set up the content in your Drupal instance, then query it using your favorite JavaScript framework and finally render it using your preferred HTML site template.
Now that we’ve cleared the air regarding the What, let’s cover the Why.
Normally, content management systems try to offer all their capabilities in a bundle: you get the core back-end with all the features you need, but you’re also given the UI which attempts to solve all the needs of their intended users.
The problem with this? Not all users have the same needs. Just off the top of my head, you have:
I’m sure you can also think about a couple of extra user types I’ve left out, but the point here is: they care about different things, so why would they need to use the same interface for all their needs?
Here is where a headless option comes in very handy because you can give each one of your users exactly what they need without losing access to the entire set of features from the CMS.
Some benefits that stem from the headless approach:
There are many benefits to a headless option with either a classic approach or a static architecture.
You will need developer resources, something you may not currently have access to if you use Drupal's integrated UI. Keep in mind that if you’re looking for a lightweight headless CMS, there are fully headless alternatives such as ButterCMS that might better suit your needs.
Let’s now review a quick example of how you can go about using Drupal’s API with your own code.
Incredibly enough, the hard part about this is not communicating with the API, which is quite easy to achieve, the unnecessarily complicated part is the configuration of the API.
I won’t cover the installation steps for Drupal, if you haven’t done that yet, please check out their full documentation on it. That being said, for the sake of simplicity, you can quickly follow these steps:
php core/scripts/drupal quick-start
Then execute this command and you’ll see the following options:
Picking the standard one will eventually complete and show you the following output:
Notice the username and the password shown there. Those are the credentials you’ll need for the first time.
With these steps, you’re ready to start working. In fact, your browser will open up a page for you to set up the new admin password. Afterward, you’re ready to log-in and start creating content.
With that, in order to enable the REST API, you’ll need to do a few things:
We’re essentially saying: add a new view called “REST View!”, which will show any item of the type “Content” and instead of creating pages or blocks, add a REST Export on the endpoint “/api/content”.
Click on “Save and Edit” and you’ll be redirected to the properties page of this view, just make sure you also add a contextual filter for it, like so:
With that, you’ve also added the ability to query “/api/content/2” to get the content with ID 2.
Make sure you save the view after this, it should look something like this:
If you have any content, you can use the preview option on this page to check it out. By default, the export will print content in JSON format, so you’ll see something like this:
And that is it! You’ve successfully enabled the REST API for Drupal. You can now consume it using that endpoint and adding the _format parameter at the end. This is important, otherwise, you’ll get weird “out of memory” errors.
Here is an example:
I’ll show you a basic example of a standard dynamic app you can create using Node.js to consume this API.
Remember the “Classic headless architecture” from above? Well here is the gist of it:
Using express-generator I’ll create a new app like so:
$ npx express test-site
$ cd test-site
$ npm install
The output from the first command will be something similar to:
And once you have the dependencies installed, you can add the views.
For this particular example, I decided to download a pre-made HTML template that you can find online for free (just search for “free web templates”). Once you’ve found the one you like, copy the entire thing into the “public” folder of this project. The folder structure should look like this:
And in my case, the template looks like this:
For the purposes of this example, I’ll be making those four highlighted images dynamic.
Now, we need to add the front-end code to pull the data from its back-end and the back-end code to pull the data from Drupal.
For the front-end code, I’ll just add jQuery on the page and use that to perform the query since we don’t need anything else. You’re more than welcome to try this with your favorite front-end framework:
Essentially inside the tag, I’ll add:
<script type="text/javascript" src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script>
const loadContent = (container) => {
const url = "http://localhost:3000/highlights?_format=json"
$.ajax({
headers:{
"Access-Control-Allow-Origin": "*",
"content-type": "text/plain"
},
crossDomain: true,
method: "GET",
url: url,
success: (resp) => {
console.log(resp)
let template = "<li><a href=\"\"><img src=\"[IMG]\" alt=\"\"></a><b>best hairstylists</b><p>[DESCRIPTION]</p></li>";
resp.forEach( item => {
const newItem = template
.replace("[IMG]", item.field_image[0].url)
.replace("[DESCRIPTION]", item.body[0].value)
$("#highlights").append(newItem)
})
}
})
}
$(document).ready( _ => {
loadContent($("#highlights"))
})
</script>
Notice how this code takes care of everything:
That’s it, this code doesn't need to do anything else. You’re free to add any extra steps you might require for your particular use case.
On the back-end side, under the “routes” folder I’ve added a new file called “highlights.js”, which will contain the new route that looks like this:
var express = require('express');
var router = express.Router();
const request = require("request")
router.get('/', function(req, res, next) {
request
.get("http://localhost:8888/api/content/?_format=json", (err, resp, body) => {
if(err) return res.json(err)
res.json(JSON.parse(body))
})
});
module.exports = router;
Again, nothing too complex, we’re just using the Request module to perform the REST query to Drupal and redirecting that response back to our client (the front-end).
Then, on the “app.js” file, we need to do a couple of changes:
1. Make sure we add the newly created route:
var highlightsRouter = require('./routes/highlights');
//...
app.use('/highlights', highlightsRouter);
2. Use the Cors module, to enable cross-domain requests (this is to enable requests from the front-end code into the back-end with no issues).
const cors = require("cors")
//...
app.use(cors())
And that is it. With these changes, you’re able to have your own dynamic app pulling data from Drupal and using it just as you see fit. Mind you, in this example we’re not doing anything to the data, but you could potentially do anything you wanted before sending it back to the front-end.
I’ve published the full source code on Github in case you’d like to check it out and directly fork it and use it on your project.
The main drawback of a headless Drupal approach is their documentation. In fact:
If you’re really interested in going headless you should consider a more dedicated service, such as ButterCMS, where we actually take the time to show you not only how to use the API but also show you practical use cases for each feature.
That being said, there are other issues you might want to consider when deciding on a headless strategy:
Leaving aside the less-than-optimal documentation and assuming you’re now too invested in Drupal to change your mind and decide for a more streamlined option, you need to understand what you’re getting yourself into.
The whole point of going headless is to gain control over the presentation and utilization of the data. The problem with that, however, is that you lose the help Drupal provided (pre-defined templates, routing and so on) and you have to add extra code to achieve your goal.
This is not a problem on teams that already have that kind of know-how. If your team has a developer and visual designer, then you’re good.
If on the other hand, you’re not a developer (nor have one on your team), the headless strategy might not be the best way to go.
It’s also important to note the difference between an actual headless strategy versus a simple REST API to query data.
A proper headless CMS needs to have an actual API-based strategy for interacting with it, and ideally, it should follow some kind of standard to improve the user experience and help with adoption. One example would be having a REST interface, something resource-based that would have a focus on the content.
Some features to look for from a proper API-based interface for a true headless experience would be:
Unfortunately, Drupal’s headless strategy excludes these key API-based strategies. You only need to set up a few things and you can query the content you added but that’s pretty much it.
With ButterCMS, you can see how to use a truly headless CMS to create a customized content management UI (something you might need if you want to have full control over your process).
Finally, with Drupal’s REST API you’re only getting the basic data you need in order to create a custom UI. If that’s all you want, that’s all you need. However, if you’re trying out a headless strategy, that might not be you.
The data returned by Drupal’s API is:
Don’t get me wrong, that data is more than enough for you to create a custom representation (it’s exactly what I did in this article, after all), but if you’re looking for a better dev-experience or a more feature-rich option, then Drupal is probably not for you.
Here you can see how Drupal compares to an actual headless CMS such as ButterCMS.
Headless CMS is nothing but a response to the current evolution of the content-management and content-exploitation paradigms. Being able to send and render content on many platforms at the same time is becoming a requirement for any business and making use of that data in other forms other than simple presentation is also becoming more common every day.
I hope that through this article I’ve been able to show you how easy it is to add this capability to your Drupal sites and why going headless is likely a requirement for your future, modern apps.
Feel free to leave a comment below if there are any questions or if you’ve managed to find a simpler way to enable the REST interface for Drupal 8.
Have a good one!
Do you want your product or marketing team to test Butter CMS? We can set up a live demo to walk your team through the fast, easy-to-use interface.