May 5, 2017

The table of contents

  1. Introduction: about headless Drupal
  2. Create React App
  3. Create Drupal API
  4. Integrate and display data
  5. Conclusion

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 web-sites, 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 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?

How to create a headless Drupal site

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 front-end framework or mobile app to Drupal and use it for displaying data. For that we must to create a Drupal RESTful API which help 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 format for an API is JSON which is provided by Drupal and almost all programming language. If program can access the web it can use a JSON API too. So we will be using it.

Why do I chose 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 user more satisfying experience. React helps us to build an interactive UI with less pain than vanilla JavaScript. Bricks-like component system gives us a 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 type and fields for it. If not, please begin with some tutorial 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:

A folder structure of React App

Step 1.2

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

<script src="https:[email protected]/dist/react.js"></script>
<script src="https:[email protected]/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 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 a 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 latest release here. 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.

Blogs content type

Step 2.4

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

The extended menu in the top navigation menu

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.

REST export settings

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.

A filter for view by a ‘Blogs’ content type

Step 2.7

Now, if you go to api/blogs page you should see 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:

Blog at Drupal website

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 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.

Was this article helpful? Click to rate: 
Average: 4.7 (28 votes)

You may also like

On some of the projects I worked on I had to build a quite powerful...
Starting with the 5th version, Drupal has jQuery out of the box. It...
Due to growth of mobile traffic responsive website design becomes...