Drupal 7 add custom feed using services

Hello, sometimes we need to add custom rss feed. We can make it using custom approach and can make it thorugh services. I prefer using services because they give us great possibilites. Services is a nice solution to integrate external applications with Drupal. Service callbacks may be used with multiple interfaces like REST, XMLRPC, JSON, JSON-RPCSOAPAMF, etc. This allows a Drupal site to provide web services via multiple interfaces while using the same callback code. I should mention that using services we can provide authentication for our feeds if needed.

So lets try to undestand what is service and what we need to create custom and service. If we had installed services module we can follow this path yoursite.com/admin/structure/services and get list of all available services. Services can be added manually using code. We will use code example in this tutorial, because it is easier to put changes on multistage environment while continuous intergration process run.

To  create custom service we should implement hook_ctools_plugin_api() and hook_default_services_endpoint() example given below with comments. Our service path consists from service path and resource path. For service we have path setting in hook_default_services_endpoint() and for resorce path will be first array key or alias which we can assing to it.

To  create custom resource we should implement hook_services_resources() I didn't find nice explanation in Internet, but found it in services module services/docs/services.services.api.php. You can read comments in this hook we can put any resource we need. 

//Please wrote code!
  /**
 * Implements hook_services_resources().
 */
function mf_feeds_services_resources() {
  $resources = array(
    'stories' => array(
      'operations' => array(
        'index' => array(
          'help' => 'List new nodes',
          'file' => array('type' => 'inc', 'module' => 'mf_feeds', 'name' => 'feeds'),
          'callback' => '_stories_resource_index',
          'access arguments' => array('access content'),
        ),
      ),
    ),
    'feed' => array(
      'index' => array(
        'help' => 'Articles feed',
        'file' => array('type' => 'inc', 'module' => 'mf_feeds', 'name' => 'feeds'),
        'callback' => '_articles_resource_index',
        'args' => array(
          array(
            'name' => 'tid',
            'type' => 'int',
            'description' => 'The taxonomy term id',
            'source' => array('path' => '0'),
            'optional' => TRUE,
          )
        ),
        'access arguments' => array('access content'),
      ),
    ),
  );
  return $resources;
}

/**
 * Triggered when the REST server request a list of supported response formats.
 *
 * @param array $formatters
 *  An associative array of formatter info arrays keyed by type extension. The
 *  formatter info specifies an array of 'mime types' that corresponds to the
 *  output format; a 'formatter class' class implements ServicesFormatterInterface
 *  and is responsible for encoding the output.
 *
 * @return void
 */
function mf_feeds_rest_server_response_formatters_alter(&$formatters) {
  $formatters['rss'] = array(
    'mime types' => array('text/xml'),
    'formatter class' => 'ServicesRSSFormatter',
  );
}

/**
 * Implements hook_ctools_plugin_api().
 */
function mf_feeds_ctools_plugin_api($owner, $api) {
  if ($owner == 'services' && $api == 'services') {
    return array(
      'version' => 3,
    );
  }
}

/**
 * Implements hook_default_services_endpoint().
 */
function mf_feeds_default_services_endpoint() {

  $endpoint = new stdClass();
  $endpoint->disabled = FALSE;
  $endpoint->api_version = 3;
  $endpoint->name = 'feeds';
  $endpoint->server = 'rest_server';
  $endpoint->path = 'feeds';
  $endpoint->authentication = array();
  $endpoint->server_settings = array();
  $endpoint->resources = array(
    'rss' => array(
      'operations' => array(
        'index' => array(
          'enabled' => '1',
        ),
      ),
    ),
  );
  $endpoint->debug = 0;
  $endpoints['feeds'] = $endpoint;

  $endpoint = new stdClass();
  $endpoint->disabled = FALSE;
  $endpoint->api_version = 3;
  $endpoint->name = 'articles';
  $endpoint->server = 'rest_server';
  $endpoint->path = 'articles';
  $endpoint->authentication = array();
  $endpoint->server_settings = array();
  $endpoint->resources = array(
    'rss' => array(
      'operations' => array(
        'index' => array(
          'enabled' => '1',
        ),
      ),
    ),
  );
  $endpoint->debug = 0;
  $endpoints['articles'] = $endpoint;

  return $endpoints;
}