Drupal 8, JSONAPI and Ember Part 1: Building a Decoupled Web App

Justin Langley
|
April 13, 2017
Image
Ember and Drupal logos

Drupal 8 and JSONAPI together make a great combination to expose content to a front-end framework. Let's see how Ember connects so easily to this combination.

Drupal 8 and JSONAPI

There have been many articles over the past year or so as the JSONAPI module has gained some serious momentum. Right now, there is currently an issue to get JSONAPI as a Drupal 8 core experimental module in 8.4! (The issue is here) The JSONAPI module implements the JSONAPI standards and exposes all Content Entities without any additional configuration needed. You can checkout the JSONAPI specs here. And there are also Drupal 8 specific docs for the JSONAPI module here (I highly recommend reading those docs before getting too far in this guide)

I will start here by assuming you know how to spin up a new Drupal 8 site (8.3 is out!) and in my example I am using Docker for Mac to run my local sites (but with this guide it shouldn't matter what you are using). So I will skip that long-winded part and skip straight to creating content types! This example here is going to create a site that has this set of content types:

  1. Blog Post
  2. Location
  3. Product
  4. Product Type

Then we will create an Ember application that will consume this data through JSONAPI endpoints and will serve as the front-end of the site. In the end you will have a fully decoupled Drupal site with Ember as a front-end.

So let's begin!

Content Types

Let's begin by downloading some desired modules for our Drupal 8 site. I've provided an example package.json file to use for this example if you'd like. (This also assume you are managing your site's dependencies with Composer, which you should! Refer here for information on managing your Drupal installation with Composer.

Now with a simple composer install we should have all of our modules. Let's install them all.

.. Great! Now that you have everything installed, let's get to the good stuff. Let's start by creating our Blog Post content type. (One of the parts I'm skipping here is setting up the Media entities and entity browser as those would require a bit more time. So where you see the images as Entity Reference fields you can just use the Image field instead.) Here's a screenshot of the fields I created:
Blog Content Type
NOTE: Instead of the field_blog_image being an entity reference field you would create it as an image field. I defaulted the Blog Content field to be the Full HTML text format and only allowed one value for the Content and Image fields.

Next let's create the Location content type! (Before creating this content type, create a taxonomy vocabulary called "Location Type" and add a couple terms.) Here are the fields:
Location Content Type
Here the Location Type field will reference the Taxonomy terms from the Vocabulary "Location Type". For the Geolocation field, for the map to work you will need to set up a Google Maps API Key and plug that into the Geolocation options under Configuration -> Web services -> Gelocation settings. Under the Manage Form Display for this form, make sure the formatter for the Geolocation field is the Geolocation Google Maps API - Geocoding and Map formatter.

Creating some content

We will start with these content types to see how they are exposed through the JSONAPI. First let's create a couple Blog Posts and a couple Locations. Once that is done, if you hit {local-site-url}/jsonapi/node/blog_post from your browser you should see an output kinda like this: Blog Post JSONAPI Response
Look at that, without doing any additional configurations the Blog Post nodes are exposed with all of the relevant info off the node! You'll also see that the image field is not in the attributes key of each node in the JSON output, but it's in the relationships key. This is because now all images are actually Entities, so the image field is actually just a reference to a file. As you can see for that relationship there is a type key with the value of file--file.

So now that we see how easy it is to expose the entities, how easy are they to consume? Well with Ember it's actually extremely simple! So let's kickoff the Ember app.


Igniting our application

First things first, make sure you're using a newer version of node (I'm currently using v7.8.0) and let's install the Ember CLI tool:
npm install -g ember-cli
And then we create our app:
ember new emberapp
And you'll see an output like this:
Installing an ember app

Ember has a built in dev server we can use to boot up the app. So from the emberapp directory let's call ember serve. The app will be served up on http://localhost:4200 and will update the app when files changes are made. It's that simple to get an Ember app going! If you haven't used Ember before, but you have used some form of MVC style JS Framework, this will feel familiar. If you have not used any MVC/MV*JS framework before, then I will go over a couple basic things about Ember (but I highly suggest reading up on it and doing the tutorial here).

Ember basics

All of your applications files will live inside the app directory. When you build the application it will get built into dist. The public directory is for any assets you want included with the app (images, fonts, etc etc). Any directories/files in public will get compiled into dist when you build the Ember app (which by the way is a simple ember build command away!).

The 4 basic building blocks of any Ember app are:

  1. Routes
  2. Models
  3. Templates
  4. Components

Routes are the defined URLs the user can/will hit inside your app.
Models are the defined data "structures" of your app (in our case they define the content types from Drupal we want to use).
Templates are Handlebars files used to render out the Apps interface based on the Route you are on.
Components are reusable Handlebars templates.

For Next time

For the next part you should play around with Ember and familiarize yourself with the handlebars syntax, as in the next post we will create the Routes, Models and Templates needed to consume the content from Drupal. Happy coding!