Headless Drupal — Build a Drupal 8 API with a ReactJS Front-End

In this tutorial I will go through setting up a ReactJS front-end with a Drupal 8 API. Some call it “Headless” Drupal, or decoupled Drupal.

Currently there aren’t many tutorials on this topic, so if I’m doing something against ‘best practices’, please let me know in the comments! :)

So let’s start.

STEP 1 — Create Your React App

1.1 Create a basic folder structure, with an index.html. I also set up SASS and Compass.

1.2 Use a CDN to add React to the index.html

1.3 Now let’s try if React works. Create a file called app.js, and call it from index.html:

<script type=”text/babel” src=”js/app.js”></script>

1.4 In app.js, let’s add a basic React ‘Hello World’ example:

ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById(‘example’)
);

1.5 And in index.html, add a <div>:

<div id=”example”></div>

If you’re using Chrome as a browser, you get a XMLHttpRequest error, since you need to use a HTTP server. On Firefox it worked, but I decided to boot up a simple (on mac, write “python -m SimpleHTTPServer” on the terminal) web server, and accessed it on http://localhost:8000/

Now we know that React works; “Hello, world!” is displayed on the browser.

> python -m SimpleHTTPServer

STEP 2 — Create Your Drupal 8 API

2.1 Next, let’s create a new Drupal installation. I’m using Drupal v.8.1.8.

2.2 On Drupal, I created a new content type called “Events”, and added three fields for it; ‘organizer’, ‘location’, and ‘date’. Then added three new events.

2.3 Under the ‘extend’ tab let’s scroll down and enable all the web services modules.

2.4 Next create a new view, I’m calling it ‘Events API’. Select the “provide a REST export” option, and give it an export path. In my case api/events.

2.5 After saving, I added a new filter criteria for the content type, so that we just get the events in the API, and not other content, such as articles or basic pages.

2.6 Now I can go to http://localhost:8888/drupalAPI/api/events and see the JSON data, or you can curl it on the terminal:

> curl http://localhost:8888/drupalAPI/api/events

2.7 Next you can enable the cors module, to be able to make API calls. If you get an error when trying to enable the module, you also need to install stack-cors and composer. On the terminal, you can require asm89/stack-cors using composer, like so: > composer require stack-cors

STEP 3- Display Data

3.1 I was first going to use jQuery on my React app, but apparently that’s frowned upon, since it impacts load time etc. And since I only need the AJAX features, loading the whole library is probably unnecessary. Therefore I’m now using Axios.

3.2 Here is my full index.html file, that I started to create in the beginning of this tutorial. Notice that I added an id=”container” on the <div>:

<!DOCTYPE html>
<html>
<head>
<meta charset=”utf-8" />
<title>App</title>
<link rel=”stylesheet” href=”https://netdna.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<link rel=”stylesheet” type=”text/css” href=”stylesheets/style.css”>
</head>
<body>
   <div id=”container”></div>
<script src=”https://npmcdn.com/react@15.3.1/dist/react.js">   </script>
<script src=”https://npmcdn.com/react-dom@15.3.1/dist/react-dom.js"></script>
<script src=”https://unpkg.com/axios/dist/axios.min.js"></script>
<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>
</body>
</html>

3.3 Now let’s display just one event title, called “Fun with Flags”. So let’s modify the app.js that we created in the beginning. I deleted the ‘hello world’ React example, and created a new React component, that gets the title from the Drupal 8 API we created.

I also created a repo for these on GitHub.

class App extends React.Component {
// Using ES6 class syntax
constructor(props) {
super(props);
   // Setting up initial state
   this.state = {
title: ‘’
}
}

// calling the componentDidMount() method after a component is rendered for the first time
componentDidMount() {
this.serverRequest = axios.get(this.props.source).then(event =>{
this.setState({
title: event.data[2].title[0].value
});
});
}
// calling the componentWillUnMount() method immediately before a component is unmounted from the DOM
componentWillUnmount() {
this.serverRequest.abort();
}

render() {
return (
<div>
<h1>Here is an event:</h1>
<h2>{this.state.title}</h2>
</div>
);
}
}
// rendering into the DOM
ReactDOM.render(
<App source=”http://localhost:8888/drupalAPI/api/events" />,
document.getElementById(‘container’)
);

3.4 And here we have it, we successfully get the title “Fun with Flags” from the Drupal 8 API, so React is working as expected!

3.5 Let’s display all the events with React, and not just one. I updated the app.js:

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

// calling the componentDidMount() method after a component is rendered for the first time
componentDidMount() {
var th = this;
this.serverRequest = axios.get(this.props.source)
.then(function(event) {
th.setState({
data: event.data
});
})
}
// calling the componentWillUnMount() method immediately before a component is unmounted from the DOM
componentWillUnmount() {
this.serverRequest.abort();
}

render() {
var titles = []
this.state.data.forEach(item => {
titles.push(<h3 className=”events”>{item.title[0].value}</h3> );
})
return (
<div className=”container”>
<div className=”row”>
<div className=”col-md-6 col-md-offset-5">
<h1 className=”title”>All Events</h1>
{titles}
</div>
</div>
</div>
);
}
}
// rendering into the DOM
ReactDOM.render(
<App source=”http://localhost:8888/drupalAPI/api/events" />,
document.getElementById(‘container’)
);

Now we can see all the event titles! I also added a header and some styling. On Github, you can see how I made the header.

Displaying all the event titles in our React app.

That’s all for now. If you have any feedback or ideas for another tutorial you would like me to write, please let me know in the comments below. Thanks!