Exposing custom Web Services

DEEPAK KUMAR   |  11th July, 2013

In this article, I will show you how to expose data from a custom table with the help of RESTful services and JSON. Such cases usually arise when you need to expose data for other sites or want mobile development for an existing Drupal site.

To do this we need Drupal 7 and services module. In addition, you will also need to create one custom table by writing code in .install file (I hope you know what I am talking about).

For this purpose, you may use drush for downloading "Services" module. Using Drush, you could type the following in terminal - drush dl services and then type drush en -y services to enable to it.

After enabling these two modules, follow the steps as mentioned below:-

1. Add a service in services UI:-

  Go to service UI page(admin/structure/services). Here, you need to enter endpoint and choose the server.

  Click on the add button and after that the following picture will be displayed.

  There you need to put machine readable name, select the server "REST" and define endpoint, here I put "setindia_api". 

Image1

  For testing purpose enable Debug mode. And then click on save to complete the process.

2. Open Resource page:-

  This page will be displayed in the service list. From there you can click on edit resources.

  You should see the following screen:-

Resource

 Resources are content available for query through the end points. As you look at the default setup, you see those resources, that come hard-coded with the Services module. But our resources is not showing there yet. We will need to create one custom module by which we will able to do so.

3. Create a Custom Module:-

If you don't know to building custom module, please refer this linkhttp://drupal.org/node/1074360, there you will find everything. Here I will only cover which is needed for build custom web services with the help of RESTful services.

For our convenience, I will call the module CUSTOM_MODULE.

4. Declare a Service Resources:-

  There is hook provided by Services module i.e hook_services_resources().

  Following is the code which we will require:-

/**
* Implements of hook_services_resources().
*/
function custom_services_services_resources() {
  $api = array(      
    'country_field_values' => array(
      'operations' => array(
        'retrieve' => array(
          'help' => 'Retrieves Country value according to country',
          'callback' => '_MYMODULE_country_retrieve',
          'access callback' => 'user_access',
          'access arguments' => array('access content'),
          'access arguments append' => FALSE,
          'args' => array(
            array(
              'name' => 'fn',
              'type' => 'int',
              'description' => 'Function to perform',
              'source' => array('path' => '0'),
              'optional' => TRUE,
            ),
            array(
              'name' => 'nid',
              'type' => 'int',
              'description' => 'Node information',
              'source' => array('param' => 'nid'),
              'optional' => TRUE,
              'default' => '0',
            ),
          ),
        ),
      ),
    ),
  );
  return $api;
}

In the code above, we declare a Resource called country_field_values, with a function "retrieve". We allow one optional parameter, "nid". The data will be accessible for a user with access content permission, and the params will be passed to a callback function _MYMODULE_country_retrieve().

5. Create the callback function():-

  Here is the callback function:-

/**
* Callback function for Country retrieve
*/
function _MYMODULE_country_retrieve($fn, $nid) {
  return queryfor_expose_country($fn, $nid);
}

Here I fetched the argument and passed it to the other function, calling it in the process. One need not call another function during return, but I do so, such that I can optimise the params I am passing to it.

6. Create the Processing function():-

Here the is required code:-

/**
* Gets COuntry data
*/
function queryfor_expose_country($fn, $nid) {
  // Compose query
  $query = db_select('country_field_values', 'cfv');
  $query->innerJoin('node', 'n', 'n.nid = cfv.nid');
  $query->innerJoin('countries', 'c', 'c.country_id = cfv.country_id');
  $query->fields('cfv')
        ->fields('n',array('title'))
        ->fields('c',array('country_name','ccode'))
        ->condition('cfv.country_id', $fn)
        ->condition('cfv.nid', $nid)
        ->range(0, 1);
  $items = $query->execute()->fetchAll();
  return $items;
}

Here we are fetching all the required component and return back.

We are almost done, so hang on.

7. Enable the resource:-

Enable the require resources, in our case we are enabling country_field_values.

Resource

After enabling the resources, type in url like this $base_url/setindia_api/country_field_values/[country_id]?nid=[nid].

Here [country_id] could be the variable which we are passing in $fn and [nid] is nid.

After hitting the above url, this will return like this:-

[
   {
      "nid":"9194",
      "country_id":"4",
      "field_name_and_value":"a:16:{s:3:\"nid\";N;s:3:\"vid\";N;s:3:\"uid\";s:1:\"1\";s:7:\"created\";i:1378400672;s:4:\"type\";s:14:\"homepage_slide\";s:8:\"language\";s:3:\"und\";s:7:\"changed\";s:0:\"\";s:31:\"additional_settings__active_tab\";s:13:\"edit-metatags\";s:6:\"submit\";s:4:\"Save\";s:13:\"form_build_id\";s:48:\"form-w8D3O1jqH6iA7P9kIGGwuMQWT7X856-3qMSVXjDXCYg\";s:10:\"form_token\";s:43:\"8kMHkqRqAxUQ4vd0R2WuNnJwpWf8TOoElqB_PFLQGik\";s:7:\"form_id\";s:18:\"geo_sensitive_form\";s:8:\"metatags\";a:13:{s:5:\"title\";a:2:{s:5:\"value\";s:26:\"[node:title] | [site:name]\";s:7:\"default\";s:26:\"[node:title] | [site:name]\";}s:11:\"description\";a:2:{s:5:\"value\";s:14:\"[node:summary]\";s:7:\"default\";s:14:\"[node:summary]\";}s:8:\"abstract\";a:1:{s:5:\"value\";s:0:\"\";}s:8:\"keywords\";a:1:{s:5:\"value\";s:0:\"\";}s:6:\"robots\";a:1:{s:5:\"value\";a:8:{s:5:\"index\";i:0;s:6:\"follow\";i:0;s:7:\"noindex\";i:0;s:8:\"nofollow\";i:0;s:9:\"noarchive\";i:0;s:9:\"nosnippet\";i:0;s:5:\"noodp\";i:0;s:6:\"noydir\";i:0;}}s:13:\"news_keywords\";a:1:{s:5:\"value\";s:0:\"\";}s:9:\"copyright\";a:1:{s:5:\"value\";s:0:\"\";}s:9:\"image_src\";a:1:{s:5:\"value\";s:0:\"\";}s:9:\"canonical\";a:2:{s:5:\"value\";s:27:\"[current-page:url:absolute]\";s:7:\"default\";s:27:\"[current-page:url:absolute]\";}s:9:\"shortlink\";a:2:{s:5:\"value\";s:28:\"[current-page:url:unaliased]\";s:7:\"default\";s:28:\"[current-page:url:unaliased]\";}s:9:\"publisher\";a:1:{s:5:\"value\";s:0:\"\";}s:6:\"author\";a:1:{s:5:\"value\";s:0:\"\";}s:15:\"original-source\";a:1:{s:5:\"value\";s:0:\"\";}}s:10:\"country_id\";s:1:\"4\";s:17:\"field_slide_image\";s:3:\"492\";s:2:\"op\";s:4:\"Save\";}",
      "created":null,
      "changed":"1378400676",
      "title":"Kaun Banega Crorepati - Slider",
      "country_name":"South Africa",
      "ccode":"SA"
   }
]

Here, country_id  I was passing "4" and nid was "9194".


This is showing like this because we are only allowing JSON.

Looking for a Drupal partner ?

We are drupal 8 ready