Some of the great news in Drupal 8 development was the introduction of web services directly in core, allowing other applications to interact with Drupal to consume exposed information or services without the need to install contributed modules.
Let’s look at the list of modules that ship with D8 core related with web services:
RESTful Web Services module in core exposes entities in different defined endpoints, while Serialization module allow to serialize entities in formats like HAL+JSON, XML, JSON. I will basically use these four modules in this blog post together with Rest UI (http://drupal.org/project/restui), a contributed module that allows to browse the available services exposed by Drupal.
To add the module we can download it from drupal.org and put it directly in /modules folder as we use to do in sites/all/modules in Drupal 7.
After enabling the module we can see the list of available resources to consume in /admin/config/services/rest
We can see the list of entities that are exposed via the REST interface and we can see how to interact with the different resources. We can also notice the node entity is enabled and we can configure several details like the authentication methods and formats availables for this resource. For now let’s not require any sort of authentication but make sure that the permissions are correctly defined. In Permissions configuration (admin/people/permissions) we will define the permission “Access GET on Content resource” to anonymous users.
Consuming webservices
So now that we verified that we have entities exposed let’s try to interact with the REST server. We will use Chrome Dev HTTP Client, a chrome extension that you can find in https://chrome.google.com/webstore/detail/dev-http-client/aejoelaoggembcahagimdiliamlcdmfm?hl=en. There are several other tools that you can use to test the endpoints including REST Client present in PHP Storm.
We will point the http request to http://yourwebsiteurl/node/1 and make sure we set a header parameter to send Accept=application/hal+json to enable HAL Json serialization before sending a GET request.
If everything went well you will receive back a node object with all fields and properties serialized in HAL+JSON. If you have problems, verify that you have enabled the right permissions, that you are passing the right headers to the correct url.
Using services views
Exposing a single entity as a resource is interesting but in Drupal world we are used to expose information that we can adapt to different format and displays using a very powerful module: Views. One of the biggest horse battles for Drupal 8 was to bring Views into Core. Not only views is in core now as it was also totally integrated with services (http://drupal.org/project/services).
Let’s use this new feature for our next example. We will list nodes from a certain content type and expose them via webservices.
We will create a new view showing nodes from a certain content type:
We will define a new display as REST export, define a path, save the view and we will check the defined output again with google dev http client
Accessing the path we defined (http://yoursitename/articles_services) we can see the output of the different exposed nodes. Views that are exposed as a REST resource can also be configured to output only the defined fields and labels.
The REST module can also be extended using plugins. Your custom modules can add plugins that will can define new REST Resources. Imagine that you want to return data associated with reviews that are provided for articles and are saved in a custom table. You could define a new REST resource in your custom module:
<?php
use Drupal\rest\ResourceResponse;
/**
* Provides a resource for database watchdog log entries.
*
* @RestResource(
* id = "article_review",
* label = @Translation("Article reviews"),
* uri_paths = {
* "canonical" = "/reviews/{id}"
* }
* )
*/
class ArticleReviewResource extends ResourceBase {
/**
* Responds to GET requests.
*
* Returns a review entry for the specified ID.
*
* @return \Drupal\rest\ResourceResponse
* The response containing the log entry.
*
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
*/
public function get($id = NULL) {
if ($id) {
$record = db_query("SELECT * FROM {reviews} WHERE id = :rid", array(':rid' => $id))->fetchAssoc();
if (!empty($record)) {
return new ResourceResponse($record);
}
}
throw new NotFoundHttpException('Review entry with ID @id was not found', array('@id' => $id));
}
}
It is clear that using Drupal to expose information using REST is way easier in Drupal 8 core without the need for contributed modules to expose entities and views results via REST in consumable and common formats. Also to extend REST layer with custom resources and functions is straightforward with the creation of custom resources.
Finally,we did not mention it in this blog post, but it also easier and safer to consume external resources in Drupal with the inclusion of Guzzle (http://guzzle.readthedocs.org/), a PHP HTTP client that makes it easy to work HTTP resources or contributed modules that leverage it like guzzle_oauth (https://drupal.org/project/guzzle_oauth).