Headless Drupal 8 - Retrieving Content Using Backbone.js

Posted by Ruben Teijeiro on Jul 29, 2014

In this post I'll explain how to decouple Drupal front-end to use your own implementation using Backbone.js and Drupal 8 as a RESTful API to retrieve the content.

This is what we call a Headless Drupal.

Drupal, Load Impact load testing

Drupal 8 front-end is going to be really attractive to front-end developers because it's using Twig template engine and because its templates have been cleaned of divitis (an interminable bunch of nested divs).

Despite this, there will be some cases where you will need to use your own front-end implementation in any framework, and request the content stored in your back-end application.

 Our Customer Success experts are happy to walk you through Load Impact and empower you to take control of your web performance. Simply click the button below to schedule a time to chat. Enjoy the Drupal lesson!

Talk to Customer Success

So let's install Drupal 8

The fastest and easiest way to do it is to use Bitnami installers. You only need to select your platform and be sure that you download the Drupal 8 version of the installer.

bitnami-installer Load Impact, load testing

Once you have downloaded the installer, just run it and follow the installation instructions. You only have to remember the user and password to login into Drupal. In my case I used user as username and password as password :P

bitnami-install, Load Impact load testing

The installer will take a few minutes to finish (a little bit more in Windows operating systems). Once it's finished you should launch the Bitnami Drupal stack so you will see the following web page:

bitnami-start, Load Impact load testing

Now you can click Access Bitnami Drupal Stack link to access to your Drupal website. Just fill the login form using the username and password you previously entered when installing the Bitnami stack.

drupal-login, Load Impact load testing

Now we need to add some content and try accessing it using a REST callback. So, let's start creating new content by clicking the Add content link.

add-content, Load Impact load testing

Select Basic page to create a basic content type with title and body. Currently there is not a way to request images or other fields through REST in Drupal 8. It is in the works however.

basic-page, Load Impact load testing

Fill title and body fields and press Save and publish button when done.

create-basic-page, Load Impact load testing

Repeat the same process to create a few content pages in order to have some data to request later. Once you have four or five basic pages press Structure in the top menu and then press Views option.

views, Load Impact load testing

A view in Drupal is a list of content where you can add and remove fields, filters and select your desired sort ordering. It's really handy to create complex pages of content.

In this case we are going to create a simple page that lists all our already created basic pages. So start pressing the Add new view button.

add-new-view, Load Impact load testing

Fill the view create form with the settings shown in the following screenshot:

view-create, Load Impact load testingNow you have a default listing of basic pages that shows only the title field. We also want to show body field, so let's add it. Press Add button in the Fields section.

view-fields, Load Impact load testing

Now select Body field from the popup window. You can find it easily using the search box, as you can see in this screenshot:

field-body, Load Impact load testing

Be careful not to select Body (body language) field. Once you have found Body field, check the checkbox and press Apply (all displays) button. Continue with default values pressing the apply button. Now you should have a view like this one:

view-save, Load Impact load testing

You can take a look at the results by pressing the Save button and browsing to the selected URL - in this case articles. So if you visit http://localhost/drupal/articles you will see a page that lists all the basic pages you already created, with title and body fields:

articles-page, Load Impact load testing

Now it's time to enable Web Services modules in Drupal to have access to this content through REST requests. Just click Extend button in the administration bar at the top. Find and enable the modules at the end of the page and press Save configuration button.

enable-ws-modules, Load Impact load testing

You will also need to configure Drupal permissions to allow REST requests. It can be done in People option in the top administration bar and by selecting the Permissions tab.

Configure the permissions to allow read requests for every user and write requests to only authenticated users, as you can see in the following screenshot:

rest-permissions, Load Impact load testing

You should now have access to the Drupal content you have created in JSON format using a GET request with CURL command, for example:

curl -i -H "Accept: application/json" http://path-to-your-localhost/drupal/node/1

The result, your Drupal node in JSON format, should look something like this:

node-json-output, Load Impact load testing

You can try to access the rest of your content using the same way with CURL command or any tool like Dev HTTP Client.

If we want to access the page with the list of contents we previously created using Views, we will have to clone it. Just visit your view configuration page again and press Duplicate as REST export button in the dropdown menu on the right.

duplicate-rest, Load Impact load testing

Now we need to change the access Path to avoid conflicts with the other page. You can do it by pressing the path link in Path Settings section, as you can see in the following screenshot:

rest-path, Load Impact load testing

If you save the view and try to access the path you have configured, using CURL command, you will get the page content in JSON format.

curl -i -H "Accept: application/json" http://path-to-your-localhost/drupal/articles/rest

You will see a lot of information related to Drupal nodes like changed and created dates , node status and node id. This is useful information if you really need it but it can considerably increase the amount of data transferred - an aspect that's really important when you accessing it using a mobile device.

Let's configure the view to provide only the data we really need, like content title and body, for example. You can start by simply changing the format from Entity to Fields and select only the fields you want. Just press Entity link in Format section on your view settings page.

rest-format, Load Impact load testing

Now change the format to Fields, press save and select Raw format for all fields, to avoid Drupal adding unnecessary field formatting.

rest-fields, Load Impact load testing

If your save these changes you can see that the JSON response contains only the data we want, which saves a lot time and data transfer.

rest-view-json, Load Impact load testing

It's time to access and display the data properly using an external application, in our case a simple Backbone.js application that makes the REST requests to Drupal, gets the data in JSON format and displays it using a template.

Let's start creating a folder for our application using the same web server provided by Bitnami.

Locate the folder where you have installed the Bitnami Drupal stack and create a folder named app using the following command:

mkdir /path-to-bitnami-drupal-stack/drupal-8.0.alpha13-0/apps/drupal/htdocs/app

We are going to place all Backbone.js application files inside this folder so consider it for the following code examples. You can find the whole application code in the following github repository:


First we need to create a index.html file where we are going to load the latest Backbone.js, Underscore.js and jQuery libraries using the following code:

<span class="s1">&lt;</span><span class="s2">script</span> <span class="s3">src</span><span class="s1">=</span>"http://code.jquery.com/jquery-2.1.1.min.js" <span class="s3">type</span><span class="s1">=</span>"text/javascript"<span class="s1">&gt;</span><span class="s3">&lt;/</span><span class="s2">script</span><span class="s3">&gt;
</span><span class="s1">&lt;</span><span class="s2">script</span> <span class="s3">src</span><span class="s1">=</span>"http://underscorejs.org/underscore-min.js" <span class="s3">type</span><span class="s1">=</span>"text/javascript"<span class="s1">&gt;</span><span class="s3">&lt;/</span><span class="s2">script</span><span class="s3">&gt;
</span><span class="s1">&lt;</span><span class="s2">script</span> <span class="s3">src</span><span class="s1">=</span>"http://backbonejs.org/backbone-min.js" <span class="s3">type</span><span class="s1">=</span>"text/javascript"<span class="s1">&gt;</span><span class="s3">&lt;/</span><span class="s2">script</span><span class="s3">&gt;</span>

The order in which you load the libraries is really important, so take it into consideration.

Now you need to create your Backbone.js application file. We are going to call it app.js and you have to load it the same way you have loaded previous libraries:

<span class="s1">&lt;</span><span class="s2">script</span> <span class="s3">src</span><span class="s1">=</span>"app.js" <span class="s3">type</span><span class="s1">=</span>"text/javascript"<span class="s1">&gt;</span><span class="s3">&lt;/</span><span class="s2">script</span><span class="s3">&gt;</span>

The Backbone.js application structure consist in the following classes:

var Article = Backbone.Model.extend(<span class="s1">{
</span>  title: <span class="s2">''</span>,
  body: <span class="s2">''
</span><span class="s1">}</span>);

The model describes the data structure, in this case the Drupal article structure that consist of title and body fields.

var Articles = Backbone.Collection.extend(<span class="s1">{
</span>  model: Article,
<span class="s3">  url: </span>'http://path-to-your-localhost/drupal/articles/rest'
<span class="s1">}</span>);

The collection is a group of model items fetched from the given URL, that points to your previously configured REST view.

var ArticleView = Backbone.View.extend(<span class="s1">{
</span>  tagName: <span class="s2">'li'</span>,
  template: _.template($(<span class="s2">'#article-view'</span>).html()),
  render: <span class="s1">function</span>() <span class="s1">{
</span>    this.$el.html(this.template(this.model.toJSON()));
<span class="s3">    return</span> this;
<span class="s1">}</span>);

We define a view to display single articles using it's own template that should be placed in index.html file, as you can see in the following snippet:

<span class="s1">&lt;</span><span class="s2">script</span> <span class="s3">type</span><span class="s1">=</span>"text/template" <span class="s3">id</span><span class="s1">=</span>"article-view"<span class="s1">&gt;
</span>  &lt;h2&gt;&lt;%= title %&gt;&lt;/h2&gt;
  &lt;%= body %&gt;
<span class="s3">&lt;/</span>script<span class="s3">&gt;

We also define a view to display the list of articles using the previous view as a subview. This view should fetch the data through a GET request explicitly called using the fetch function.

This is not the best way, but I will describe in my next blog post how to do it using routers. In the next post, I will also demonstrate how to create and delete articles using POST requests.

In the meantime, I suggest you test the code samples and try different template implementations, adding more fields to the view.

Questions or comments? Post them below or Tweet them to me @rteijeiro

See you in the next post ;)

Topics: Drupal 8, jQuery, Bitnami, REST API, front-end decoupling, Headless Drupal, Underscore.js, RESTful API, GIT, content management system, Twig template engine, backbone.js, CMS, Blog

Posts by Topic

see all
Try a Free Test