fromSeptember 2014
Article:

Building a Self-Documenting REST API

Endpoints, Routing, and Entity Fields
0

Blindfolded Typing Competition Building rest endpoints with Drupal 8 is a snap. With the Rest UI module, fieldable entities, and the range of field-types in core, a site-builder can readily toss together a HAL+JSON REST server. Lists can be created with views using the REST export display type.

But any API is only as good as its documentation. Wouldn't it be great if Drupal could build out this documentation for us – and keep it current as we make changes?

API Documenation /node/{node}

REST API Documentation in the PHP World

Looking to our open source PHP cousins in Symfony, the NelmioApiDoc bundle generates documentation by parsing doc-blocks on each controller method.

But in Drupal, the REST endpoints are fully-dynamic methods in the REST module's controller. The REST and Serialization modules integrate with the Entity Field API to dynamically introspect the properties of each entity type and bundle. In theory, we should be able to do the same to build out our documentation by leveraging the information APIs in the Entity-Field and Routing APIs.

Providing Business Rules

We can use Drupal to introspect the available routes and the required fields for each end-point, but we can't capture business rules for each field. First we need to specify those rules for each field. Luckily, if we're doing things right, we've already accomplished this by adding help text when we created the field – so we’ll re-use that to build our documentation.

Finding the Endpoints

We first need to find the endpoints we wish to document. In the routing system, Drupal\Core\Routing\RouteProvider is responsible for loading and returning routes. However, it doesn't provide a method to fetch routes matching a pattern; we need to know the route names. And in order to introspect all routes – and to return those that come from the Rest module and those from the Views module that relate to a REST export display – we need to get a list of route names that are prefixed with rest. or view.. Fortunately, the routing system fires events before new routes are saved and when route building is finished. To react to these events, we need an event listener. We also need access to the Entity Manager and Views executable services to introspect the Views module routes and see which contain a REST Export display.

We define our event listener using a service.yml file, then tell Drupal that we want to react to the routing alter, and then route finished events. In the alter event-listener, we inspect the routes and flag those relating to views with REST Export displays – or from the REST module itself – and track their names using the State Key-Value store. We now have the routes, so we can start creating documentation for each of them. The full contents of the subscriber can be seen at rest_api_doc.

Building the Documentation

We want our documentation overview to be at /api/doc, and details for each route at /api/doc/{path}, grouping together routes that share a common path for discoverability. We define those routes using a routing.yml file, and build out a controller class to contain our callbacks. The overview method is fairly straightforward: we re-use the list of routes we collected earlier to present a table of contents; we expose a text-area field via a settings form to allow an administrator to enter some overview text; and we use the RouteProvider to return a discrete list of REST end-points by path for the given route names. The overview looks like this:

API Documentation Overview / List of End-points

End-point Details

Each route that is based on an entity-type contains parameters relating to the content being sent or received. For example, a node end-point will contain the node-id for GET, PATCH, and PUT operations. This is encapsulated in the parameters in the route path, as well as in the route requirements and options. We can inspect this detail in the routes using the Routing API, and use this to build out the documentation. By getting the parameters from each route, we can determine the entity-type. We can then examine the field and property data: Here it becomes a little convoluted.

Most traditional REST APIs would have an end-point for each type of object, and the properties of that object would be largely consistent. But Drupal has the notion of entity-type bundles. For the Node entity-type, these are represented by node-types. The fields that make up one node-type would ordinarily be completely different from the fields that make up another node-type. But from a REST perspective, with Drupal core, these two (or more) node-types share the same end-point. So the fields you must send for POST, PUT, and PATCH operations – as well as the content you receive back from GET requests – will vary wildly, depending on the bundle (node-type) of the item sent or requested. And, of course, it isn't limited to the node entity-type; taxonomy, comment, and blocks all have a notion of different fields for different bundles/types.

To get around this we list base-fields first, and then configurable fields specific to each bundle.

API Documentation /entity/taxonmy_term

Summary

Drupal 8 is a leap forward in REST capabilities from Drupal 7: the Routing and Entity-Field APIs contain built-in information discovery. That helps developers quickly discover the properties and attributes of route and entity objects, and can also be used by Drupal to document itself.

All the code described here has been turned into the Self Documenting Rest API module. Let's continue the conversation in the issue queue for the project.

Image: "Blindfolded Typing Competition" by Foxtongue is licensed under CC BY-NC-SA 2.0

Advertisement

From our blog

Entity Storage, the Drupal 8 Way

In Drupal 7 the Field API introduced the concept of swappable field storage.

The Drupal 6 to 8 Upgrade Challenge - Part 2

Having concluded the readiness assessment, we turn next to migrating the content and configuration. In reality, there’s little chance that we would migrate anything but the blogs from our old site. For the sake of giving Migrate in Core a workout with real conditions, however, we’re going to upgrade with core’s Migrate Drupal module rather than rebuilding.

The Drupal 6 to 8 Upgrade Challenge - Part 1

Nathaniel Catchpole , the Drupal 8 release maintainer and Tag1 Senior Performance Engineer, suggested that Drupal shops everywhere could support the

DrupalCon Austin

The entertainment industry is not for the faint of heart.

Drupal Watchdog Joins the Linux New Media Family
Drupal Watchdog 6.01 is the first issue published by Linux New Media.

Drupal Watchdog 6.01 is the first issue published by Linux New Media. Come see the Drupal Watchdog team at DrupalCon 2016!

Drupal Watchdog was founded in 2011 by Tag1 Consulting as a resource for the Drupal community to share news and information. Now in its sixth year, Drupal Watchdog is ready to expand to meet the needs of this growing community.

Drupal Watchdog will now be published by Linux New Media, aptly described as the Pulse of Open Source.

Welcome to DrupalCon Barcelona - The Director's Cut

For all you schedule-challenged CEOs – and ADHD coders – this Abbreviated Official Director’s Cut is just what the doctor ordered.

Welcome to DrupalCon - The Barcelona Edition

Did we have fun in Barcelona?
OMG, yes!

Did we eat all the tapas on the menu and wash them down with pitchers of sangria?
Yes indeed!

Recursive Closures and How to Get Rid of Them

This came up while manipulating taxonomy children and their children recursively, so it’s as not far from Drupal as you’d think.