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.
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 node/1.json, node/1.xml or node/1.rdf too.
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.
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.
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.
The main differences are:
node/1, user/1. We do not see a need to have multiple endpoints for the same resource in a RESTful desgin.For more about the relation and partial overlap to the Services module, read and participate in the discussion over at http://drupal.org/node/1042512.
You might be interested in the output, so here is the output the module currently produces for a testing-node:
JSON:
{
"nid":"3",
"vid":"3",
"is_new":false,
"type":"article",
"title":"asdfdsf",
"language":"und",
"url":"https:\/\/example.com\/node\/3",
"edit_url":"https:\/\/example.com\/node\/3\/edit",
"status":"1",
"promote":"1",
"sticky":"0",
"created":"1294913241",
"changed":"1296405309",
"author":{
"uri":"https:\/\/example.com\/user\/1",
"id":"1",
"resource":"user"
},
"log":"",
"revision":null,
"comment":"2",
"comment_count":"0",
"comment_count_new":"0",
"body":{
"value":"\u003cp\u003etest2\u003c\/p\u003e\n",
"summary":"\u003cp\u003eha\u003c\/p\u003e\n",
"format":"filtered_html"
},
"field_tags":[
],
"field_image":[
],
"field_test":"1",
"field_file":[
]
}
The same node in XML:
<?xml version="1.0" encoding="utf-8"?>
<node>
<nid>3</nid>
<vid>3</vid>
<is_new/>
<type>article</type>
<title>asdfdsf</title>
<language>und</language>
<url>https://example.com/node/3</url>
<edit_url>https://example.com/node/3/edit</edit_url>
<status>1</status>
<promote>1</promote>
<sticky>0</sticky>
<created>1294913241</created>
<changed>1296405309</changed>
<author resource="user" id="1">https://example.com/user/1</author>
<log/>
<revision/>
<comment>2</comment>
<comment_count>0</comment_count>
<comment_count_new>0</comment_count_new>
<body>
<value><p>test2</p>
</value>
<summary><p>ha</p>
</summary>
<format>filtered_html</format>
</body>
<field_tags/>
<field_image/>
<field_test>1</field_test>
<field_file/>
</node>
And finally in RDF/XML:
<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description xmlns:site="https://example.com/" xmlns:dc="http://purl.org/dc/terms/" xmlns:sioc="http://rdfs.org/sioc/ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:og="http://ogp.me/ns#" rdf:about="https://example.com/node/3">
<rdf:type rdf:resource="http://rdfs.org/sioc/ns#Item"/>
<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Document"/>
<site:nid xmlns:site="https://example.com/">3</site:nid>
<site:vid xmlns:site="https://example.com/">3</site:vid>
<site:is_new xmlns:site="https://example.com/"/>
<site:type xmlns:site="https://example.com/">article</site:type>
<dc:title xmlns:dc="http://purl.org/dc/terms/">asdfdsf</dc:title>
<site:language xmlns:site="https://example.com/">und</site:language>
<site:url xmlns:site="https://example.com/">https://example.com/node/3</site:url>
<site:edit_url xmlns:site="https://example.com/">https://example.com/node/3/edit</site:edit_url>
<site:status xmlns:site="https://example.com/">1</site:status>
<site:promote xmlns:site="https://example.com/">1</site:promote>
<site:sticky xmlns:site="https://example.com/">0</site:sticky>
<dc:date xmlns:dc="http://purl.org/dc/terms/" rdf:datatype="xsd:dateTime">1294913241</dc:date>
<dc:modified xmlns:dc="http://purl.org/dc/terms/" rdf:datatype="xsd:dateTime">1296405309</dc:modified>
<site:author xmlns:site="https://example.com/">
<rdf:Description rdf:about="https://example.com/user/1"/>
</site:author>
<site:log xmlns:site="https://example.com/"/>
<site:revision xmlns:site="https://example.com/"/>
<site:comment xmlns:site="https://example.com/">2</site:comment>
<sioc:num_replies xmlns:sioc="http://rdfs.org/sioc/ns#" rdf:datatype="xsd:integer">0</sioc:num_replies>
<site:comment_count_new xmlns:site="https://example.com/">0</site:comment_count_new>
<content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/">
<rdf:Description>
<site:value xmlns:site="https://example.com/"><p>test2</p>
</site:value>
<site:summary xmlns:site="https://example.com/"><p>ha</p>
</site:summary>
<site:format xmlns:site="https://example.com/">filtered_html</site:format>
</rdf:Description>
</content:encoded>
<dc:subject xmlns:dc="http://purl.org/dc/terms/">
<rdf:Description/>
</dc:subject>
<og:image xmlns:og="http://ogp.me/ns#">
<rdf:Description>
<site:alt xmlns:site="https://example.com/"/>
</rdf:Description>
</og:image>
<site:field_test xmlns:site="https://example.com/">1</site:field_test>
<site:field_file xmlns:site="https://example.com/">
<rdf:Description/>
</site:field_file>
</rdf:Description>
</rdf:RDF>
Comments
Greg
Mon, 01/31/2011 - 15:11
Permalink
Awesome!!
This looks very VERY cool... light API for sites that just want to expose content quickly and easily. Obvious feature request would be collections of entities via Views (perhaps a Views Display). But with that there should be no other features... just a really light Services alternative. I *love* this. =)
Steven
Mon, 03/07/2011 - 17:19
Permalink
JSONP
Hi - nice module. I installed it on a fresh Drupal to see if I could use it to consume entities from a separate webapp. It seems the parameters after the .json in the request cause the normal HTML page to be returned rather than the object definition wrapped in a callback. Do I need to add something to the module code to get this to work? or is it already there? or is this not the right module for doing JSONP? any help getting this to work is greatly appreciated.
fago
Mon, 03/07/2011 - 18:35
Permalink
There is no JSONP as of now.
There is no JSONP as of now. But please, let's use the modules issue queue for any specifc questions.
Steven
Mon, 03/07/2011 - 19:24
Permalink
Done
Added a request in the module issues queue
Nicolas
Tue, 06/07/2011 - 22:12
Permalink
fantastic!
I find your module very interested and well written. I have been working with it couple of days and I'm wondering how can I read a tree of nodes in JSON, is it possible to retrieve more than one node? something like: $entity_type/$id1 $id2 $id3.json?
Good Job!
Gracias!
Dimas
Fri, 06/10/2011 - 18:02
Permalink
I'm afraid this will not be
I'm afraid this will not be RESTfull.
Rimbuaj
Tue, 07/05/2011 - 16:03
Permalink
Image fields
Hey, ¿what about image fields?, it could show the url or something?
Anonymous
Thu, 10/13/2011 - 11:43
Permalink
Yes What about Image Fields, media fields ?
Yes What about Image Fields, media fields ?
moltra
Fri, 02/24/2012 - 21:13
Permalink
new to RESTful
I am trying to use your module to get a list of terms from a Taxonomy list. Then this list will be used to select one term and pull a list of nodes with that term and fields.
Can I do this with your module? Also does this module work with the drupal search?
The site I am hoping to use it with is www.serviidb.com
Nate Dunham
Wed, 04/11/2012 - 19:28
Permalink
I'm wondering if this module
I'm wondering if this module is fully functional with the drupal search?
Forex Brokers
Michée
Sat, 05/19/2012 - 10:58
Permalink
REST Client entities
I am wondering if is there a RESt Client module to receive these entities in another Drupal sites. I would like to share my entities between Drupal sites like that.
Michée
Sat, 05/19/2012 - 10:58
Permalink
REST Client entities
I am wondering if is there a RESt Client module to receive these entities in another Drupal sites. I would like to share my entities between Drupal sites like that.
Ashvin
Tue, 03/26/2013 - 11:46
Permalink
RESTFUL Without login
Hi fago
Really very simple to use. Great Work.
But i was wondering how can i use webservices without login to drupal site, actually i want to use Entity details in iPhone app.
can you please suggest me to use webservices without login or any alternet way..?
Add new comment