{ Hi! I'm Mike }
I'm a core developer with The Horde Project and a founding parter of Horde LLC - the company behind the world's most flexible groupware platform. This is my personal blog full of random thoughts about development and life in general.
March 29, 2008

Using the Horde API to Power External Sites or Applications - Part 1

Every Horde application contains a powerful external API that is used by other Horde applications to communicate with each other.  For example, the address book features within IMP are implemented by communicating with Turba via Turba's API.  Fortunately, this same API can be used by the web developer for communicating with Horde from other websites or applications - even if they reside on different servers.

In this part of the series, we will examine the basics of communicating with Horde's API through the Horde Registry object. In the next part we'll look at getting the same information from a Horde install that is running on a different server - through the RPC interface.

First off, let's talk about the Registry. As the Horde Wiki says, "The Registry is the glue that holds all the applications together."  All API methods are called through the Registry object. Even if you are interacting with Horde through it's RPC server, ultimitely, the API is being called through Registry::call().  To put it simply, when using the Registry to use another application's functionality, the Registry is responsible for knowing what application provides the functionality and where to find the code that implements it. It also ensures that the code runs in the correct application scope or context. See the wiki page for more information on the Registry.

The API itself is defined in each applications' lib/api.php file.  There you will find that application's interface to the external world.  For example, let's start with something simple. Horde's base API has a method for retrieving the list of currently installed and registred Horde applications, called horde/listApps. Probably not very useful for an external website, but it's a good, simple place to start.  The code required to to call this method - when your Horde install is on the same server as your website/application would look like this:

<?php
// Define the path to Horde
define('HORDE_BASE', '/path/to/horde');
// Load the Horde Framework Core
require_once HORDE_BASE . '/lib/core.php';
// Create a registry object
$registry = &Registry::singleton();
// Make the call
$apps = $registry->call('horde/listApps');
?>

This will return the list of applications that are available and registred with Horde. Note that this does not take any kind of authentication into account yet, so the list will only include applications that have SHOW permissions to the world.

Next, let's try an API call that requires a user to be authenticated. Turba has an API method that returns the list of address books a user has access to: contacts/sources. You'll notice that the method names follow a simple pattern. They are in the form of apiName/apiMethod.  For example, with Turba, all api methods start with contacts.  For the Horde base api, as you saw above, they start with horde.  Kronolith, the calendaring application, would start with calendar.  Simple, huh?  Now, the code:

<?php
// This is the same as above
define('HORDE_BASE', '/path/to/horde');
require_once HORDE_BASE . '/lib/core.php';

// Tell Horde we will deal with Authentication
define('AUTH_HANDLER', true);

// Get a registry object
$registry = &Registry::singleton();

// ...and authenticate
$auth = &Auth::singleton($conf['auth']['driver']);
$auth->authenticate('username',
                    array('password' => '***'));

// Make the call
$apps = $registry->call('contacts/sources'); 

This returns an array of sources the user has access to, indexed by source key. You could then take the source key, and use it in another API method such as contacts/search and use it to search that address book. To do that we need to pass parameters to the API method.  This next example demonstrates how to do just that. The contacts/search method takes 4 parameters, but we are only going to worry about the first three for this example:

<?php
define('HORDE_BASE', '/horde');
require_once HORDE_BASE . '/lib/core.php';

// Tell Horde we will deal with Authentication
define('AUTH_HANDLER', true);

$registry = &Registry::singleton();
// But now we have to authenticate
$auth = &Auth::singleton($conf['auth']['driver']);
$auth->authenticate('myname',
                    array('password' => '***'));

// Make the call
$sources = $registry->call('contacts/sources');

// Note the second parameter to the call()
// function. It's an array containing all the
// parameters the api call requires. In this case
// we are passing three parameters: 
//   An array of search terms
//   An array of sources to search
//   An array of the fields to search
$results = $registry->call('contacts/search',
                           array(array('michael'),
                                 array_keys($sources),
                                 array('name')));

You now have a basic understanding of interacting with Horde's API.  Next  time, we'll look at getting the same information from Horde that we did in this article, but we will do it using Horde's RPC interface, so we can communicate with a Horde install located on a seperate machine, across the network. We'll also start to look at Horde_Blocks and how they provide a quick, easy way to get blocks of Horde content onto your own site.

Some resources that you may find useful: