Web services
Mumble
Table of contents
Introduction
Guzzle
Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and trivial to integrate with web services. Features:
- Simple interface for building query strings, POST requests, streaming large uploads, streaming large downloads, using HTTP cookies, uploading JSON data, etc.
- Can send both synchronous and asynchronous requests using the same interface.
- Uses PSR-7 interfaces for requests, responses, and streams. This allows you to utilize other PSR-7 compatible libraries with Guzzle.
- Abstracts away the underlying HTTP transport, allowing you to write environment and transport agnostic code; i.e., no hard dependency on cURL, PHP streams, sockets, or non-blocking event loops.
- Middleware system allows you to augment and compose client behavior.
Documentation:
- docs.guzzlephp.org (Top)
- docs.guzzlephp.org (Quickstart)
- Stack Overflow (tagged "guzzle")
- Gitter (guzzle/guzzle)
Installing Guzzle
To install Guzzle using composer, put the
following composer.json
in the module that will
need Guzzle:
{ "require": { "guzzlehttp/guzzle": "^6.3" } }
When you later enable the module with drush, all dependencies will be sorted out.
Using
For a Drupal module to be able to use Guzzle it needs the following two lines:
require_once 'sites/all/vendor/autoload.php'; use GuzzleHttp\Client;
Then the following may be used.
$client = new \GuzzleHttp\Client(); $res = $client->request('GET', 'https://api.github.com/repos/guzzle/guzzle'); echo $res->getStatusCode(); // 200 echo $res->getHeaderLine('content-type'); // 'application/json; charset=utf8' echo $res->getBody(); // '{"id": 1420053, "name": "guzzle", ...}' // Send an asynchronous request. $request = new \GuzzleHttp\Psr7\Request('GET', 'http://httpbin.org'); $promise = $client->sendAsync($request)->then(function ($response) { echo 'I completed! ' . $response->getBody(); }); $promise->wait();
Here is an example of setting up basic authentication and checking the response.
$client = new GuzzleHttp\Client(); $res = $client->get('http://www.example.com/endpoint', [ 'auth' => [ 'username', 'password' ] ]); $statuscode = $res->getStatusCode(); debug($statuscode, 'statuscode');
Provided all went well, the call to debug()
will
output “200”.
Services
The Services provides Drupal with a standardized solution for building API's so that external clients can communicate with Drupal. Out of the box it aims to support anything Drupal core supports. It provides a code level API (through sub-modules for REST and XMLRPC) for other modules to expose their features and functionality via HTTP or HTTPS. It provide Drupal plugins that allow others to create their own authentication mechanisms, request formats, and response formats.
This case study describes how to set up a RESTful Web Service (RWS), using leveraging on the contributed Services project. It will also discuss how to test it and finally describe how to build a native ToDo-app for Android to interact with this web service.
For introductions to RWS, please see Alex Rodriguez: RESTful Web services. Basic principles of REST Web services and Zell Liew: Understanding And Using REST APIs. For more background information you may also want to read the Wikipedia article about Representational_state_transfer.
Install Drupal Services
Before you start familiarise yourself with these software resources and informatio sources:
- Services (Drupal project, version 7.x-3.24).
- Drupal Groups: Services
- Drupal modules using Services
- Spyc (PHP library).
- cURL (CLI tool to make HTTP-requests).
- RESTED (Firefox plugin, GitHub (documentation), Espen Henriksen (creator).
The documentation is extensive, but spread over several books and some of it is outdated. Here are links to the most relevant parts.
- Top level book.
- Services version 3.
- Testing Services with the node resource.
- Creating a resource for Services 3.x.
This chapter is based upon these writings.
The Services API is on the project's /docs
folder:
services.authentication.api.php
– hooks related to authentication pluginsservices.servers.api.php
– servers definition hooksservices.services.api.php
– definition of new servicesservices.versions.api.php
– how to write versioned resources
These variables may be set:
services_{$resource}_index_page_size
– this variable controls maximum number of results that will be displayed by index query. See services_resource_build_index_query() for more information.services_generate_error_body
– boolean denoting whether a message body should be included with certain HTTP error-related status codes. (According to IETF's RFC2616, 204 and 304 responses must not include bodies.)
These steps are required to set up Services and make it ready for testing:
- Intall dependencies (CTools and Libraries).
- Install and enable Services.
- Install latest version of Spyc (library version 0.6.2). Rename from “Spyc.php” to “spyc.php” and install in directory “
servers/rest_server/lib
” under the project's root directory. - Enable sub-module REST Server
- Install cURL for the CLI
- Install RESTED plugin for Firefox
The main Services controls are found if you navigate to
.To create a new service definition Click on the “Add” link. To import a service definition that has been exported from another Drupal website, use the “Import” link.
Services are defined as “endpoints”. An endpoint is a unique URL stem that acts as a base for all calls. Each endpoint is defined by a combination of URL, server, and authentication. So for instance you could define two REST services, one authenticated and one available for anonymous users, with unique URLS like:
http://example.com/api/anonymous
http://example.com/api/authenticated
In addition to defining a unique URL, the service definition specifies what type of server is used to return data requests (e.g., REST, XMLRPC, etc.):
After the service has been created, you can click the link in its “Edit Resources”-button in the “Operations”-column for the resource to define it further. Thos produces five tabs:
- Edit: Edit the same settings as was set when the service was added (except Machine-readable name of the endpoint).
- Server: Specify what response formatters to send and receive information (e.g., JSON, XML, etc.) and the parser type to enable for te REST server.
- Authentication: Define a system for user authentication (e.g., session authentication, oAuth). Initially, only session authentiction is available.
- Resources: Specify what type(s) of entities the service is able to handle (e.g., nodes, users). Clicling on the small triangle to the left of a resource expands a menu to let you specify what types of actions are permitted for each information type. This includes CRUD operations along with non-CRUD actions such as listing items, attaching a file, etc.
- Export: Export your service definition as code so that it can be imported elsewhere.
Pressing the small triangle to the right of the link expands a drop-down menu that links to the same items as the tabs described above, and three additional ones (Disable/enable, Delete, Clone).
- Edit resources: Resources tab.
- Edit server: Server tab.
- Edit authentication: Authentication tab.
- Edit: Edit tab.
- Disable/Enable: Disables or enables the resource.
- Delete: Deletes the resource.
- Clone: Create a clone of the resource.
- Export: Export tab.
Test Drupal Services
You can test whether Services is working by enabling a resource and retrieving that resource.
For this first test, disable all authentication. You can enable the authentication later after you have confirmed that the service you have created is returning results as expected.
For the purpose of this test, we will assume that you have created
a REST service where the machine-readable name of the endpoint is
“test_service
” with the path to thepoint endpoint being “test”. When
you edit your service it should look like this:
Using the node resource for testing is a good way to get started because creating nodes is easy in Drupal and because the Services module provides the full range of CRUD methods for nodes: create, retrieve, update, delete (and index).
Since you have not enabled authentication, Services has no way of associating your request with a user ID and will treat all requests as coming from an anonymous user. In order to retrieve node information, therefore, the “View published content” permission must be enabled for the anomymous user.
Yu must enable response formatters and request parsing under the
Server tab. For this test, enable json
and xml
and application/json
.
The URI for the resource is put together from the information configured under the “Edit” tab for the resource. Below is both the formula and an example of the URI to get node 6 from a web service installed on a site named “example.org” provided the path to the endpoint is “test”:
http[s]://your_domain/your_endpoint_path/your_resource_path.response_format http://example.org/test/node/6.json http://www.copymarks.org/test/node/6.json
Enable the resource that may be consumed under the Resources tab. You do this by putting a checkmark in the box to the left of the resource. For this test, enable “node”. Also enable the operations that will be allowed for the resource. For this test, enable all of them. When done, press “Save”.
If you only specify a single response formatter, it will be
returned by default (and you can leave out the response format part of
the URI). If you enable more than one, xml
is the
default (assuming that the web service has XML enabled). You may add
the desired response format to the URI. You do this by adding a period
followed by the abbreviation for that response format to the end of
the URL. If the requested response format is not enabled, the server
returns 406 (Unknown or unsupported response format).
The RESTful interface uses the following methods:
- retrieve:
GET
. - index:
GET.
- create:
POST
. - update:
PUT
. - delete:
DELETE
.
It takes a little more effort to put
together POST
, PUT
and DELETE
methods, so we'll start by testing some “retrieve” and “index”
requests.
To retrieve the example node using cURL:
$ curl http://www.example.org/test/node/6.json { "vid":"6", "uid":"1", "title":"Welcome!", …
Screendump of retrieving the sme node using the RESTED firefox plugin:
ToDo project
Create a Todo resource project that will contain our service
implementation. The .info
file could look something like
this:
name = ToDo Resource description = Sample resource implementation core = 7.x dependencies[] = services
Final word
[TBA]
Last update: .2019-04-21 [gh].