During the work on my thesis over the last year, I played around a lot with RESTful services based upon the Entity API. What I needed was a simple service that just exposes Drupal's entities in a RESTful manner, while obeying Drupal's permission and access systems. Now, me and klausi have created a small module that does exactly that: Restful web services.
So how does it work?
The module makes use of the Entity API and the information about entity properties (provided via
hook_entity_property_info()) to provide resource representations for all entity types (nodes, comments, users, taxonomy terms, ..). It aims to be fully compliant to the REST principles. Drupal's entities are exposed at the unified
$entity_type/$id paths, while respecting the Content Accept/Content Type headers of the HTTP requests. That means if a client requests
node/1 with usual HTTP accept headers it will get Drupal's usual output, if it requests
node/1 while accepting only JSON, it will get the JSON representation of the node. Similarly, all CRUD operations are supported as common for RESTful services. Then, the module supports GET requests on paths like
As mentioned above, the solution just obeys Drupal's permission and access system. If there is an active session and the user has sufficient permission for the request, it will be served. So any add-on authentication strategies would have to plug into Drupal's usual user system. For example, the RestWS module comes with a small add-on module that authenticates users via HTTP basic authentication. So you can define a regular user for a client, configure their access permissions as usual, and just pass its credentials with a request.
So what about the property information?
The module makes use of the property information the entity API collects for all entity types, as well as the accompanying wrapper classes. While the API also allows providing non-entities as resources, it requires the existence of property information. Representations of entities are provided according to their property information. What does that mean?
So let's have a look at an example: The node author. In the property information about nodes, there is no
uid property, instead there is an 'author' property, pointing to the according user entity. So the module makes use of that information to output a proper reference to the author, being the author's URI (URIs are the proper way to do references in RESTful designs). So instead of just outputting user id as
uid property with an integer value, we output a proper reference to the node's author. Apart from that, the property information includes access permissions - so updating the node author will only be possible if you have sufficient permissions.
Then the property information could be used to provide a description of the web service for the caller, in a human as well as in a machine-readable way.
Which formats are supported?
The module currently comes with support for JSON, XML and RDF/XML whereas modules may add more formatters. As the property information is available to the formatters too, it's possible to do formatters that output some properties in a certain way, e.g. using a special XML namespace. Similarly the RDF formatter looks up the RDF mapping being defined for a property, in order to generate meaningful RDF output.
What's different to the Services module?
The main differences are:
* RestWS provides only RESTful services (no message-oriented or RPC-style web services like SOAP, XML-RPC etc.).
* RestWS strongly builds upon the Entity API and its property information, thus utilizes it for CRUD, access checks, getting property information, ..
* Property information is built into the API, so formatters may make use of it to format the data in a sensible way.
* There are no "service endpoints" to configure as resources are just available at uniform paths like
user/1. We do not see a need to have multiple endpoints for the same resource in a RESTful desgin.
1. Full CRUD for the Entity APIIn the long-term I want to see the Entity API becoming our main CRUD-API, on which modules may build upon. For D8 I do think for every entity should be based upon a class implementing the "EntityInterface", which provides some simple methods to easily access identifiers, revision ids, labels, uris as well as save(), delete(), .. methods.
2. Improved DX for fieldsNow, we have two kind of entity properties: Fields and non-fields. So should one use an entity property or a field? We have some nice APIs around fields, but they are not built for daily developer usage so programmatically re-using fields is no fun. Still, developers can go without a field for any custom data storage, but then we are loosing all the advantages fields come with - like flexible storage or the awesome module support (which I've tried to solve in D7 via hook_entity_property_info()). Once we have improved DX for fields in place, developers can easily embrace it and benefit from its advantages.
3. Everything is a fieldSo why not adopt fields for any entity property? So we could make entity properties easily translatable via the field API and benefit from the improved out-of-the-box module integration and stuff already written for fields, like widgets and formatters . Of course, some fields need to be hidden from the UI then.
4. Storage APIsWith everything being a field, entity data would be scattered around in lots of db tables. Also, it should be possible to use the API to register any remote data object as entity. So we need to have entity-storage and field-storage backends, such that also the remote-data-entity can have fields stored in the local database. Thus, with everything being a field we need to allow developers to delegate field-storage to the entity.
5. Describing dataAlso, as of now field types have to describe the db schema to be used for saving. However, the schema API is built for the database system so it has no notion of describing stuff beyond it, like that a timestamp is a date. So maybe the contract between the storage API and the field system should not be the db schema, but an actual description of the data to be saved. I.e. instead of telling the system to save an integer which will be used for saving a node id, tell it that it has to save a reference to a node. Apart from that, the described data structure is what other APIs built around fields (widgets, formatters) have to use (or should use -> query), just as any developer working with fields. So simultaneously, modules making use of entities and their fields could rely on that information, e.g. to determine all entity references or just to get some data values of a certain type, e.g. textual values for token replacements.
6. Profile2 in coreWith 1) in place, it should be rather easy to replace our old profile module with something new built upon entities and fields like profile2. We'll see how profile2 does for d7.
7. Rules in coreI'd really like to work on bringing a slightly simplified version of the foundational API of rules into core, thus re-placing the current action system. However with Rules 2.x the whole API is built around the way of describing data utilized for hook_entity_property_info() as well as on entities. Thus for Rules in core making sense, it would need something comparable in core - e.g. point 5).
After about a year full of work around Drupal 7, Rules & Web services I recently graduated my master studies "Information & Knowledge Management" at the Vienna University of Technology. As finally my thesis will be presented officially with others at this year's epilog, I thought it would be a good time to share my thesis to the public.
The thesis title is "Event-Condition-Action rules for distributed content management", thus I've worked on a re-architectured version of Rules that is able to work across system boundaries, e.g. multiple Drupal installations. That resulted in Rules 2.0 as well as stuff like the Entity API being created - but better, it finally made it possible for me to fully concentrate on working on Drupal - awesome!
Thesis abstract: For the popular open source Content Management System (CMS) Drupal the Rules extension module makes it feasible for users to configure reactions on a high level without requiring any programming expertise. To achieve that, the extension allows for the specification of reactive rules - or more precisely it leverages Event-Condition- Action rules, for which the actions are executed when a specified event occurs and the conditions are met. Finally the ability to create custom reactions constitutes an opportunity for users to rapidly adapt the behavior of Drupal based web applications. In this thesis the existing Rules extension module is analyzed and revised in order to obtain an extensible and reusable solution, for which all identified flaws have been eliminated. Moreover the module is advanced to work across system boundaries, such that it can be utilized for the rule-based invocation of web services as well as for reacting on remotely occurring events. Therefore the solution obtains the ability to work with arbitrary data structures with the help of metadata, so that the data of remote systems can be seamlessly integrated based on metadata. Building upon this capability we present the rule-based utilization of RESTful and WS* web services and introduce Rules web hooks - a novel approach for the interaction of Drupal based web applications that exploits reaction rules to enable custom near-instant reactions on remotely occurring events.Get the full-text of the thesis at http://wolfgangziegler.net/thesis. At this point, let me thank my employer epiqo for sponsoring this work, as well as my academic advisors O.Univ.Prof. Dipl.-Ing. Dr.techn. A Min Tjoa and Mag. Dipl.-Ing. Dr. Amin Anjomshoaa of the Institute of Software Technology and Interactive Systems, who already did a great job supporting the Drupalcamp Vienna 2009.
git push dev? Well with Git that's pretty easy to achieve. First create a new Git repository on the remote if you haven't yet:
git checkout your-branch
git checkout -f
git config receive.denycurrentbranch ignore