Using the Services module in Drupal 7 to create a REST API

Using the Services module in Drupal 7 to create a REST API

Adding an API to your Drupal site doesn’t have to be difficult, well…not too difficult. Using the Services module removes a lot of the work needed and sets you up for an easy implementation. Its especially nice with its hooks and it outputs everything in json format and handles error messaging.

I won’t get into the admin/UI side of the Services module, but this is the code to create a new REST server for the Services module.

This will be an open API with no authentication, but I’ll throw in a permission in there just in case we want to limit this later to a certain user role. Once again, this is just a basic code example.

/**
 * Implements hook_permission().
 */
function mymodule_permission() {
  return array(
    'mymodule get nodes' => array(
      'title' => t('Get nodes via mymodule REST API'),
    ),
  );
}

/**
 * Implements hook_services_resources().
 */
function mymodule_services_resources() {
  return array(
    'get_nodes' => array(
      'index' => array( // 'index' is used when no parameters are passed using GET
        'help' => 'Retrieves drupal nodes',
        'callback' => '_mymodule_get_nodes',
        'access callback' => '_mymodule_access',
        'access arguments' => array('index', 'node'),
        'access arguments append' => FALSE,
      ),
    ),
    'retrieve' => array( // 'retrieve' is used when a parameter is passed using GET
      'help' => 'Retrieves a specific node',
      'callback' => '_mymodule_get_node',
      'args' => array(
        array(
          'name' => 'nid',
          'optional' => FALSE,
          'source' => array('path' => 0),
          'type' => 'int',
          'description' => t('The node nid to retrieve.'),
        ),
      ),
      'access callback' => '_mymodule_access',
      'access arguments' => array('view', 'node'),
      'access arguments append' => FALSE,
    ),
    /*
     *  some other additional methods are
     *  'create' => POST
     *  'update' => PUT
     *  'delete' => DELETE
     */
  );
}

/**
 * Access callback function.
 */
function _mymodule_access($op = 'view', $type, $args = array()) {
  switch ($op) {
    case 'index':
    case 'view':
      if ($type == 'node' && user_access('mymodule get nodes')) {
        return TRUE;
      }
      break;
  }
}

/**
 * index callback function.
 */
function _mymodule_get_nodes() {
  $items = array();
  $query = db_select('node', 'n');
  $query->fields('n', array('nid', 'title'));
  $query->orderBy('n.title', 'ASC');
  $results = $query->execute()->fetchAll();
  foreach ($results as $r) {
    $item[] = array(
      'nid' => $r->nid,
      'title' => $r->title,
    );
  }
  if (!count($items)) {
    return services_error('no nodes found, 404);
  }
  return $items;
}

/**
 * retreive callback function.
 */
function _mymodule_get_node($nid) {
  if (is_numeric($nid)) {
    $node = node_load($nid);
    if ($node->nid) {
      $item = array(
        'nid' => $node->nid,
        'title' => $node->title,
      );
      return $item;
    }
  }
  return services_error('node not found, 404);
}

This is about as short as I can get it. You should do additional security checks and basic validation, but you get the idea :)

It would also be great to add a way of limiting the ‘index’ by adding parameters/arguments, since it could get crazy to return ALL nodes of your site
www.mysite.com/api/get_nodes?start=150&count=100

Good Luck!

Comments are closed.