Getting Your First REST Server Working
If you have never dealt with services before, then this guide may help you get a REST server on Drupal 7 up and running.
I have pulled this example module from other sources and made one small edit to it, of adding ->fetchAll() to the create function, but all you have to do is to install 1) the Services module, 2) the REST server within the Services module package, 3) this custom module below, and 4) the Firefox plugin called "Poster" (which allows you to check that everything is working). You can do this on any Drupal 7 site, as far as I know.
NOTE: The instructions written below are to get you up and running in your local environment so you understand how to make the site with a working REST server. Following these steps and not doing anything further may leave your site vulnerable.
You may also download the archive attached with files containing all the code shown here.
Check the documentation on hook_services_resources for a concise explanation of some of the arguments (Services REST Server module API).
Here is the custom "noteresource" module to install:
noteresource.info:
name = Note Resource
description = Sample resource implementation
package = Notes example
core = 7.x
files[] = noteresource.inc
noteresource.install:
<?php
// noteresource.install
/**
* Implementation of hook_schema().
*/
function noteresource_schema() {
$schema['note'] = array(
'description' => t('Stores information about notes.'),
'fields' => array(
'id' => array(
'description' => t('The primary identifier for a note.'),
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
),
'uid' => array(
'description' => t('The user that created the note.'),
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'created' => array(
'description' => t('The timestamp for when the note was created.'),
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'modified' => array(
'description' => t('The timestamp for when the note was modified.'),
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'subject' => array(
'description' => t('The subject of the note'),
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
),
'note' => array(
'description' => t('The note'),
'type' => 'text',
'size' => 'medium',
),
),
'primary key' => array('id'),
);
return $schema;
}
?>
noteresource.module:
<?php
// noteresource.module
/** Gets a note object by id.
*
* @param int $id
* @return object
*/
function noteresource_get_note($id) {
return db_query('SELECT * FROM {note} WHERE id=:id', array(':id' => $id))
->fetchAll();
}
/** Writes a note to the database
*
* @param object $note
* @return void
*/
function noteresource_write_note($note) {
$primary_key = !empty($note->id) ? array('id') : NULL;
drupal_write_record('note', $note, $primary_key);
}
/**
* Deletes a note from the database.
*
* @param int $id
* @return void
*/
function noteresource_delete_note($id) {
db_query('DELETE FROM {note} WHERE id=:id', array(':id' => $id));
}
/**
* Implementation of hook_services_resources().
*/
function noteresource_services_resources() {
return array(
'note' => array(
'retrieve' => array(
'help' => 'Retrieves a note',
'file' => array('file' => 'inc', 'module' => 'noteresource'),
'callback' => '_noteresource_retrieve',
'access callback' => '_noteresource_access',
'access arguments' => array('view'),
'access arguments append' => TRUE,
'args' => array(
array(
'name' => 'id',
'type' => 'int',
'description' => 'The id of the note to get',
'source' => array('path' => '0'),
'optional' => FALSE,
),
),
),
'create' => array(
'help' => 'Creates a note',
'file' => array('file' => 'inc', 'module' => 'noteresource'),
'callback' => '_noteresource_create',
'access arguments' => array('note resource create'),
'access arguments append' => FALSE,
'args' => array(
array(
'name' => 'data',
'type' => 'struct',
'description' => 'The note object',
'source' => 'data',
'optional' => FALSE,
),
),
),
'update' => array(
'help' => 'Updates a note',
'file' => array('file' => 'inc', 'module' => 'noteresource'),
'callback' => '_noteresource_update',
'access callback' => '_noteresource_access',
'access arguments' => array('update'),
'access arguments append' => TRUE,
'args' => array(
array(
'name' => 'id',
'type' => 'int',
'description' => 'The id of the node to update',
'source' => array('path' => '0'),
'optional' => FALSE,
),
array(
'name' => 'data',
'type' => 'struct',
'description' => 'The note data object',
'source' => 'data',
'optional' => FALSE,
),
),
),
'delete' => array(
'help' => 'Deletes a note',
'file' => array('file' => 'inc', 'module' => 'noteresource'),
'callback' => '_noteresource_delete',
'access callback' => '_noteresource_access',
'access arguments' => array('delete'),
'access arguments append' => TRUE,
'args' => array(
array(
'name' => 'nid',
'type' => 'int',
'description' => 'The id of the note to delete',
'source' => array('path' => '0'),
'optional' => FALSE,
),
),
),
'index' => array(
'help' => 'Retrieves a listing of notes',
'file' => array('file' => 'inc', 'module' => 'noteresource'),
'callback' => '_noteresource_index',
'access callback' => 'user_access',
'access arguments' => array('access content'),
'access arguments append' => FALSE,
'args' => array(
array(
'name' => 'page',
'type' => 'int',
'description' => '',
'source' => array(
'param' => 'page',
),
'optional' => TRUE,
'default value' => 0,
),
array(
'name' => 'parameters',
'type' => 'array',
'description' => '',
'source' => 'param',
'optional' => TRUE,
'default value' => array(),
),
),
),
),
);
}
?>
noteresource.inc:
<?php
// noteresource.inc
/**
* Callback for creating note resources.
*
* @param object $data
* @return object
*/
function _noteresource_create($data) {
global $user;
if (isset($data) && is_array($data)) $data=(object) $data;
unset($data->id);
$data->uid = $user->uid;
$data->created = time();
$data->modified = time();
if (!isset($data->subject)) {
return services_error('Missing note attribute subject', 406);
}
if (!isset($data->note)) {
return services_error('Missing note attribute note', 406);
}
noteresource_write_note($data);
return (object)array(
'id' => $data->id,
'uri' => services_resource_uri(array('note', $data->id)),
);
}
// noteresource.inc
/**
* Callback for updating note resources.
*
* @param int $id
* @param object $data
* @return object
*/
function _noteresource_update($id, $data) {
global $user;
$note = noteresource_get_note($id);
unset($data->created);
$data->id = $id;
$data->uid = $note->uid;
$data->modified = time();
noteresource_write_note($data);
return (object)array(
'id' => $id,
'uri' => services_resource_uri(array('note', $id)),
);
}
/**
* Callback for retrieving note resources.
*
* @param int $id
* @return object
*/
function _noteresource_retrieve($id) {
return noteresource_get_note($id);
}
/**
* Callback for deleting note resources.
*
* @param int $id
* @return object
*/
function _noteresource_delete($id) {
noteresource_delete_note($id);
return (object)array(
'id' => $id,
);
}
function _noteresource_index($page, $parameters) {
global $user;
$notes = array();
$res = db_query('SELECT * FROM {note} WHERE uid=:uid ORDER BY modified DESC',
array(':uid' => $user->uid));
foreach ($res as $note) {
$notes[] = $note;
}
return $notes;
}
/**
* Access callback for the note resource.
*
* @param string $op
* The operation that's going to be performed.
* @param array $args
* The arguments that will be passed to the callback.
* @return bool
* Whether access is given or not.
*/
function _noteresource_access($op, $args) {
global $user;
$access = FALSE;
switch ($op) {
case 'view':
$note = noteresource_get_note($args[0]);
$access = user_access('note resource view any note');
$access = $access || $note->uid == $user->uid && user_access('note resource view own notes');
break;
case 'update':
$note = noteresource_get_note($args[0]->id);
$access = user_access('note resource edit any note');
$access = $access || $note->uid == $user->uid && user_access('note resource edit own notes');
break;
case 'delete':
$note = noteresource_get_note($args[0]);
$access = user_access('note resource delete any note');
$access = $access || $note->uid == $user->uid && user_access('note resource delete own notes');
break;
}
$access = TRUE;
return $access;
}
?>
Now, enable Services, REST server, and Note Resource modules.
For our example our site will be at http://localhost/drupal-7.7. Go to http://localhost/drupal-7.7/admin/structure/services/list/. Click "Add". Name it "notes", select "REST" for the server, enter "note" in the "Path to endpoint", check off the "Debug mode enabled" and "Session authentication" checkboxes, and then click the Save button.
Go to http://localhost/drupal-7.7/admin/structure/services/list/notes/resources. Check off "notes" and "login" (under user) then click Save. Go to http://localhost/drupal-7.7/admin/structure/services/list/notes/server and check off "application/x-www-form-urlencoded" under "Request parsing" and click Save.
Now open the Poster add-on for Firefox by clicking Tools (F10 to show dropdown menu for newer version of Firefox) and then "Poster". Visit its add-on page.
[These instructions were verified and updated as per comment below.]
You'll need to login first so use the following settings:
URL:"http://localhost/drupal-7.7/note/user/login"
Parameters tab: (add the following "Name" -> "Value")
username -> your drupal username
password -> your pass
form_id -> user_login
Click "Content to send" tab
Content Type: 'application/x-www-form-urlencoded'
Click "Body from parameters"
Then click "POST"
After logging in, you can now post the note:
URL:"http://localhost/drupal-7.7/note/note"
Content Type: application/x-www-form-urlencoded
Parameters tab and add the following:
Name: "subject" - Value: "First note of mine"
Name: "uid" - Value: "1"
Name: "note" - Value: "Note 1. Note 1. Note 1. Note 1. Note 1. Note 1. "
Name: "modified" - Value: "1312988453"
Name: "created" - Value: "1312988453"
Content Type: 'application/x-www-form-urlencoded'
Click the "Body from Parameters" and then "POST"
Now if you look in your database you will see an entry in the Note table. You can also now see it by (without changing anything) clicking the GET button in Poster.
You can find explanations for why I did each step by going to http://drupal.org/node/783460.
Help improve this page
You can:
- Log in, click Edit, and edit this page
- Log in, click Discuss, update the Page status value, and suggest an improvement
- Log in and create a Documentation issue with your suggestion