Create a headless Drupal website

How to create a headless Drupal site

Introduction: about headless Drupal

In my previous article "RESTful Web Services in Drupal 8: quick start guide" I just mentioned some possibilities that arise from a decoupled Drupal approach. One of them is an opportunity to build a Drupal site with separate back-end and front-end. Why headless Drupal became a trend in a few past years? First of all, it makes a developer’s life easier: back-end and front-end teams can work separately from each other. Another advantage is an ability to serve content on the growing numbers of websites, back-end systems, different types of applications and multiple devices, such as IoT devices, wearables and more. All of these abilities are based on the web services principles.

That’s where our knowledge of a RESTful API from the previous article will come in handy. In this article, I will show you an example of a decoupled site. For the front-end part of an application we will be using React and for the back-end, we will be using Drupal (as usual). You will see how different parts of the application can communicate with each other and in the end, you will have an understanding of how to build your own decoupled Drupal site and how to extend it in several ways.

But first of all: what does the “headless” (or decoupled) mean?

Headless Drupal
Headless Drupal

Usually, when someone opens the Drupal site in a browser he (or she) sees the themed output (head) that Drupal generates by itself. Thus with the decoupled approach, we handle Drupal’s job of creating and displaying HTML to the front-end framework like Angular or Backbone.js. Drupal still deals with the back-end part and it is used as a content management system but now it’s “headless”. So we can link the front-end framework or mobile app to Drupal and use it for displaying data. For that, we have to create a Drupal RESTful API which helps us to exchange data between the different parts of the application and connect them all together.

I already mentioned in the previous article that one of the most popular formats for an API is JSON which is provided by Drupal and almost all programming languages. If a program can access the web it can use a JSON API too. So we will be using it.

Why do I choose React? React is the most used JavaScript library and it’s chosen by many companies and developers for its fast and smooth user interface (UI). It gives the user a more satisfying experience. React helps us to build an interactive UI with less pain than vanilla JavaScript. The bricks-like component system gives us the possibility to create a complex UI. More information about React you can find here.

This article is less theoretical and more practical. Also, I assume you are already familiar with Drupal and know how to add new content types and fields for it. If not, please begin with some tutorials over the Internet first.

Create React app

First of all, let’s create a React App. It’s where the decoupled Drupal website originates. We will create a simple welcome page.

Step 1.1

This is a simple basic folder structure with nothing extra:

React app: a basic folders structure
React app: a basic folders structure

Step 1.2

I will use a cdn to add React to my index.html file:

<script src="https://unpkg.com/react@15/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@15/dist/react-dom.js"></script>

Step 1.3

Now let’s add a <div> in index.html:

<div id="container"></div>

Step 1.4

Create a file app.js inside js folder and add “React is awesome!” example:

ReactDOM.render(

<h1>React is awesome!</h1>,
document.getElementById('container')
);

Step 1.5

Also include babel to transform JSX syntax (from the previous step) into ECMAScript and include app.js file inside index.html:

<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.24/browser.min.js"></script>
<script type="text/babel" src="js/app.js"></script>

Now, if you try to open the index.html file in your Chrome browser (in Firefox it seems to work without advantage) you should have the “XMLHttpRequest” error. That means you need to use an HTTP server to make it work. The simplest way to start a new server is to use PHP's 5.4 and later built-in web server. You need to evaluate this command inside of our React app directory:

php -S localhost:8000

Now if you go to  http://localhost:8000/ page you should see “React is awesome!”. It means that React works and we’re ready to go.

Create Drupal API

Step 2.1

First of all, let’s create a new Drupal installation. For your convenience, it’s recommended to choose a standard Drupal installation over the minimal because of advanced features which make navigation and site administration more comfortable. You can always find the latest release here. The version of Drupal in my example is 8.2.6.

Step 2.2

Now it’s time to add a new content type called “Blog”. Let’s create basic blog-like fieldset:

  • Title
  • Body
  • Image

Since title and body fields are available by default in the new content type, you only need to add an “Image” field.

Step 2.3

Create a few nodes of “Blogs” content type.

The "Blogs" content type
The "Blogs" content type

Step 2.4

Click on the extended menu in the top navigation menu and enable all modules under the web services.

Enabling Drupal modules
Enabling Drupal modules

Step 2.5

Now it’s time to create a required Web Service by adding a new view. I called it ‘Blogs API’. Click the ‘Provide a REST export’ checkbox and enter REST export path. In my case, it’s api/blogs.

Web Service
Web Service

Step 2.6

After saving it, I also added a filter for this view by content type ‘Blogs’. It’s made for getting only blogs in API and not other content types like an article or a basic page.

The "Blogs" content type
The "Blogs" content type

Step 2.7

Now, if you go to api/blogs page you should see JSON data.

JSON data
JSON data

Integrate and display data

Step 3.1

I chose the axios client for the server request instead of jQuery because I need only AJAX features and I don’t want to load the whole library (jQuery). So add this into index.html:

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

Step 3.2

Here is the full content of my app.js file. We will display all the blogs nodes:

class App extends React.Component {
 constructor() {
  super();
  // Set up initial state
  this.state = {
    data: []
  }
}

// after a component is rendered for the first time call the componentDidMount() method
componentDidMount() {
  var th = this;
  this.serverRequest = axios.get(this.props.source)
    .then(function(blog) {
      th.setState({
        data: blog.data
      });
    })
}

// call the componentWillUnMount() method before a component is unmounted from the DOM
componentWillUnmount() {
  this.serverRequest.abort();
}

render() {
  var titles = [];
  this.state.data.forEach(item => {
    titles.push(<h3 className="blogs">{item.title[0].value}</h3> );
  });
  return (
    <div className="container">
      <div className="row">
          <h1 className="title">Blogs:</h1>
          {titles}
      </div>
    </div>
  );
}
}

// render into DOM
ReactDOM.render(
<App source="http://localhost:8888/api/blogs" />,
document.getElementById('container')
);

Step 3.3

Now go to http://localhost:8000/ and you should see something like this:

Headless Drupal blog
Headless Drupal blog

When I tested it for the first time I got this error in my browser: “No 'Access-Control-Allow-Origin' header is present on the requested resource”. A problem was in the cross-domain request (more information about it is here). So installation of the Chrome extension solved the problem. 

Conclusion

Decoupled Drupal isn’t a magic elixir which will make your site super fast in a minute. In order to get a satisfying result, I’d recommend you to pay attention to a UI localization, search engines indexing problems (cannot properly index a website with client-side JS), less layout control by site builders, overhead and overlooked content. If you want to try something different and taste the future of Drupal it’s your turn to face new challenges and try to solve them with this approach.

Useful links: 

1. Why you should migrate your site to Drupal

2. OOP in Drupal 8 and how to use it to create a custom module

3. How to create a headless Drupal site

4. How to send the JSON data from a Drupal 8 site?

You might also like