The term "database shards" makes me giggle.
Drupal Services Module
Drupal is an extremely powerful and flexible content management system, and is a very strong foundation for a data-driven website. However, there are times when a solitary website just isn't enough -- for example you may want to have one main site and a number of affiliated sites, you may want to write a stand-alone application that can interact with your Drupal site, or you may want to share data between a Drupal site and a non-Drupal site. Situations like this call for a web service!
A web service is typically an API (application programming interface) that is hosted on a web server and exposed to the internet. One shining example of web services in our daily lives occurs every time you click the Submit button in an online shopping cart. A web service is responsible for telling the vendor that your credit card is valid and has enough room for you to make your purchase. Web services are also used to get your shipping quotes and reserve your tracking number.
The long and the short of it is that web services let websites talk to websites, websites talk with applications, and applications talk to applications.
Now, there are a number of different web service protocols (RPC, SOAP, AMF, REST, etc.). One of the drawbacks to web services is that they tend to be tied to a specific protocol, which means that you have to package up whatever data you wish to send to a web service in the protocol expected by the web service. If you are consuming multiple web services, it's quite possible that you'd have to package your data several different ways. To use the ecommerce example from above, you may have to package your order information (number of packages, each package's weight, source and destination addresses, etc.) for a SOAP-based shipping quote web service, and the customer's payment information for a REST-based credit card authorization service. This creates a lot of unnecessary complication in the world of web service consumption.
With all this in mind, when you sit down to write your own web service, where do you begin? What protocol should you use? How are you going to make the great behemoth of possibility that is Drupal available as a web service without sacrificing all that great power and flexibility by hard-coding your service to serve up only certain types of nodes and fields?
The beautiful answer is you don't have to think about any of that.
Enter the Services module. (http://drupal.org/project/services)
Services is a web service layer for Drupal that lets you check a few boxes and turn your Drupal website into a full-blown web service. In the Drupal tradition, Services is flexible and extensible. It separates the protocol used to transmit the data from the api that drives it. Out of the box, it contains the XML-RPC server module, but at the time of this writing there are modules to add JSON, JSON-RPC, REST, SOAP, and AMF compatibility. Each server module adds its own path. Changing protocols is as easy as changing the URL that the consuming application uses to connect. You can also easily write your own server module to define your own protocol or support one that does not already exist.
http://www.example.com/services/xmlrpc
http://www.example.com/services/json-rpc
http://www.example.com/services/super-awesome
etc.
The Server module also comes with a number of included services: node, comment, file, menu, search, system, taxonomy, user, views, and node_resource. Each service provides a number of methods, such as user.login, node.get, comment.save, taxonomy.selectNodes, etc. Using these services, you could write a stand-alone application that can sign in to your drupal site (user.login), read a node (node.get) and post a comment (comment.save) without ever having to crack open a web browser or parse a single line of HTML.
Just as with the protocols, adding your own services is very simple and straightforward. The Services module uses the protocol server module to parse the incoming data and then presents the data to your service module in a predictable, documented format. This means that you can write your custom service and not only will it be able to consumed simultaneously via SOAP, RPC, and SUPERawesome (your custom protocol), but it will also be able to consumed via protocols that have not even yet been defined.
In addition to the API, the Services module also provides a handy UI that lets you test any exposed methods by providing data directly into a form. Method help and argument description text can be provided by the service developer, and is displayed on this form.
Finally Services provides a number of options on the security front. If you don't feel comfortable opening up your website to any old web service, you can enable API Key Authentication which requires that a pre-created set of credentials be provided or your request will be rejected. You can also enable Session-based authentication requiring a valid session id to be presented with each call to verify that you're still the same consumer who connected/logged in previously. Finally, each service method can even provide its own access check so you could potentially have the ability to define which specific methods a particular role has access to.
I'll close out this exploration with a code sample showing you how little it takes to create a custom service module.
ExampleModule.info
name = "Example Service Module"
description = "Demonstrates creating a new service module"
package = "Services - services"
dependencies[] = services
core = "6.x"
ExampleModule.module
function ExampleModule_disable() { cache_clear_all('services:methods', 'cache'); } function Example_enable() { cache_clear_all('services:methods', 'cache'); } function ExampleModule_service() { '#method' => 'example.echo', '#callback' => 'ExampleModule_echo', '#name' => 'text', '#type' => 'string', '#optional' => TRUE, '#description' => t('Enter the string that the server should return.') ), '#return' => 'string', '#help' => t('Echos the provided string back to the consumer.') ), ); } function ExampleModule_echo($text = "") { if($text == "") return services_error(t('There was no text provided to echo'), 404); }



Comments
Thanks for such an informative article.
Drupal design
I've been looking web service implementation to retrieve drupal themes from TotalTheme.com, similiar to Wordpress "Install theme" feature. Awesomeee. Thanks for making this available. The custom service module really helps.
Post new comment