JavaScript and Drupal 8 RESTful Web Services

This page aims to outline how to use JavaScript to communicate with Drupal 8's RESTful services. It is broken into sections per entity type.

It outlines:

  1. which HTTP method to use (GET, POST, PATCH, or DELETE) on which URL
  2. which headers to send
  3. what response can be expected from the server

For the following entity types:

WSCCI Conversion Guide - Best practices

Separate controller objects for different return types

All controller methods in the same class should be intended for use with the same route key i.e.: they should all be intended for use with _content or _controller, but not a mix of both. For example,

Underlying functionality of the routing system in Drupal 8

The Drupal 8 routing system builds a great deal on the Symfony framework. To define and use routes, you don't necessarily need to know the Symfony concepts, but for more advanced use cases, knowing the background helps a lot.

Drupal 8 uses the Symfony HTTP Kernel. That is a system which gets the request and asks other systems to produce the requested output (a response object) and sends the response back to the client. The output is generated by piece of code called the controller. In theory the controller can be either a pure PHP 4 like function, a method on an object or even an anonymous function.

Symfony routing compared to Drupal routing

As module developer you define the list of routes and the corresponding controllers, for example:

  path: '/taxonomy/autocomplete_vid/{taxonomy_vocabulary}'
    _controller: '\Drupal\taxonomy\Controller\TermAutocompleteController::autocompletePerVid'
    taxonomy_vocabulary: \d+

Most Symfony documentation mentions pattern, but Drupal decided to just allow the non-deprecated 'path' key in its routing file.

WSCCI Conversion Guide - Pass 2

Dig deeper into our new controller class

So far it doesn't seem like we've gotten much out of this work. The class will now lazy load for us, but that's about it. Where it becomes useful is dependencies.

A dependency is some other object or code that our code leverages. There are two kinds of dependencies: Hard dependencies are those that are hard coded into our code and cannot be changed without rewriting. Injected dependencies are objects that we pass into our object explicitly, which means we can change them by passing in different objects that have the same interface. That makes code more cleanly separated, makes it clearer what dependencies we have, and makes testing far easier.

There are lots of ways to go about separating and injecting dependencies. For now, we'll show one example: both of our new controller methods call book_get_books(), making that a hard dependency. Instead of having a random function floating around that we cannot test, let's convert that into a service. A service is simply any object that 1) is managed by the service container and 2) gets its own dependencies from the service container. Otherwise there's nothing special about them.

WSCCI Conversion Guide - Pass 1

1. Leverage the new routing system

First, we need to switch the declaration of the routes (the mapping rules) to the new routing system. The new routing system doesn't use a hook but a YAML file, book.routing.yml, that is placed in the root of the module directory.


  path: '/book'
    _content: '\Drupal\book\Controller\BookController::bookRender'
    _permission: 'access content'

  path: '/admin/content/book'
    _content: '\Drupal\book\Controller\BookController::adminOverview'
    _permission: 'administer book outlines'

There's a lot going on here, so let's take it one step at a time.

Every route has a machine name. By default, using the name of the page callback function we're replacing is usually fine. Then there are three key sections for each route.

This is the path, what would have gone in the $items array as a key in hook_menu. Note that the path must begin with a / and may consist of not more than 9 parts each separated by a /. Also note that any placeholders are marked with {}, rather than %. More on that later.

WSCCI Conversion Guide

This guide is a basic tutorial for the process of converting legacy page callbacks to new-style controllers. It is not a guide for porting from Drupal 7 to Drupal 8; it assumes that you're working with a fairly recent copy of Drupal 8 HEAD. (A contrib module guide for porting from Drupal 7 to Drupal 8 can be based off of this document later.)

We will demonstrate the process by looking at the Book module in core. These are real-live examples (based on a true story!) of a core callback getting converted. Some snippets have been reformatted or tweaked to help illustrate a point. There are a lot of moving parts, so we'll take it in several passes and build up our understanding of what is going on. (This example taken directly from this issue.)

If you want to help with the conversion (please do!), see any issue with the WSCCI-Conversion tag or stop by #Drupal-WSCCI in IRC.


Subscribe with RSS Subscribe to RSS - wscci