Daniel Ansari’s blog Random software musings

December 10, 2008

How to use the REST API in Elgg 1.1

Filed under: Open Source — Tags: , , — admin @ 3:50 pm

The Elgg documentation describes the REST API rather superficially, yet provides no samples, and is now inaccurate for the recent versions of Elgg.

After a minor modification to your .htaccess file, using the REST API is very simple, and, in many cases, avoids the need to create individual files in your Elgg root directory to provide custom functionality.

First, let’s look at how your API method would be called:

http://localhost:8080/elgg/pg/api/rest?method=login&username=dansari&password=apples

Let me explain technically what’s going on first. Any API calls in Elgg are handled by a page handler, i.e., when the HTTP request begins with /pg/..., the .htaccess (containing mod_rewrite rules) tells Apache to use the Elgg file engine/handlers/pagehandler.php to handle the request. Elgg then determines which page handler to use, and invokes it. The REST API is known as an “API endpoint”. In this case, because the next part of the URL is rest, the API page handler passes control to the file services/api/rest.php.

The problem with the .htaccess that ships with Elgg is that it would cause the page handler to be invoked as pagehandler.php?handler=api&page=rest, discarding the querystring entirely. services/api/rest.php actually expects the method parameters to be in the querystring, so to get this to work, we simply change the following line in .htaccess:

RewriteRule ^pg\/([A-Za-z\_\-]+)\/(.*)$
engine/handlers/pagehandler.php?handler=$1&page=$2

to this:

RewriteRule ^pg\/([A-Za-z\_\-]+)\/(.*)$
engine/handlers/pagehandler.php?handler=$1&page=$2 [QSA]

Here is the code for a sample REST method, which would be implemented via a plugin. For this example, the following file is located at mod/rest_login/start.php (NB I had to put a space character before the ?php in line 1 for WordPress to render this listing):

  1. < ?php
  2.  
  3. function rest_login_init() {
  4. expose_function('login', 'rest_login_handler', array(
  5. "username" => array("type" => "string"),
  6. "password" => array("type" => "string")
  7. ), "", "GET", false, true);
  8. }
  9.  
  10. function rest_login_handler($username, $password) {
  11. $persistent = "1";
  12. $result = false;
  13. if (!empty($username) && !empty($password)) {
  14. if ($user = authenticate($username,$password)) {
  15. $result = login($user, $persistent);
  16. }
  17. }
  18. return $result;
  19. }
  20.  
  21. // Add the plugin's init function to the system's init event
  22. register_elgg_event_handler('init','system','rest_login_init');
  23.  
  24. ?>

The important differences between what is stated in the Elgg documentation and here are:

  • There is no register_method function. Instead, use expose_function as in line 4.
  • "type" must be specified for each parameter, as in lines 5-6.

Finally, here is an excerpt from engine/lib/api.php, which explains the parameters in more detail:

  1. /**
  2. * Expose an arbitrary function as an api call.
  3. *
  4. * Limitations: Currently can not expose functions which expect objects.
  5. *
  6. * @param string $method The api name to expose this as, eg "myapi.dosomething"
  7. * @param string $function Your function callback.
  8. * @param array $parameters Optional list of parameters in the same order as in your function, with optional parameters last.
  9. *       This array should be in the format
  10. *   "variable" = array (
  11. *                                       type => 'int' | 'bool' | 'float' | 'string' | 'array'
  12. *                                       required => true (default) | false
  13. *        )
  14. * @param string $description Optional human readable description of the function.
  15. * @param string $call_method Define what call method should be used for this function.
  16. * @param bool $require_auth_token Whether this requires a user authentication token or not (default is true).
  17. * @param bool $anonymous Can anonymous (non-authenticated in any way) users execute this call.
  18. * @return bool
  19. */
  20. function expose_function($method, $function, array $parameters = NULL, $description = "", $call_method = "GET", $require_auth_token = true, $anonymous = false)

There are limitations of the REST API, one of them being that the return value is rendered in a view. You can override the view by including the directory structure and file views/default/api/output.php in your module directory, but Elgg will still render it as HTML; if you need to process the result, you will need to parse this HTML. Also, if you decide to override this view, it will be overridden for any REST API method calls, not just the one implemented in your module.

One particular limitation of the sample above is that it does not authenticate! At least I couldn’t get it to work; the reason is that the API method is registered as not requiring a user authentication token. As a result, the method executes in unauthenticated fashion, and when authenticate() is called to attempt to authenticate the user, it always succeeds – regardless of the password – because pam_authenticate() returns true for the executing method. (Hopefully this would make sense to you if you’ve written an authentication plugin.)

9 Comments »

  1. Great post. Have you added the htaccess issue to the bug tracker?

    Comment by Cash — December 10, 2008 @ 8:53 pm

  2. Thanks a lot for the comment. I just got this blog really off the ground today.

    I haven’t got involved yet in the bug tracker, but now that you mention it, I will – cheers.

    Comment by admin — December 10, 2008 @ 11:03 pm

  3. thanks for such a nice post.
    i tried the above sample code and it works for me
    now i need to use other functions like Add blog, Add friend etc. through Rest API
    is it possible to use ??

    If you have something in that area will be helpful..

    thanks again..

    Comment by Narendra — December 30, 2008 @ 5:44 am

  4. Your ticket was closed yesterday: http://trac.elgg.org/elgg/ticket/622

    Comment by Cash — December 30, 2008 @ 1:22 pm

  5. Thanks for the info; I commented on that ticket.

    Comment by admin — December 31, 2008 @ 5:42 pm

  6. Simplifying XML-based RESTful services in Elgg…

    elgg is a PHP-based social networking wonder that we’ve been using at Medullan for some internal stuff lately.  One of my interests was to see what type of tooling could be built around it – desktop widgets, firefox extensions, etc.  It appeare…..

    Trackback by ryannorris.com — February 3, 2009 @ 12:51 pm

  7. To fix the authentication problem, you need to fix line 168 in engine/lib/sessions.

    Change:

    if (pam_authenticate(array(‘username’ => $username, ‘password’ => $password)))

    To:

    if (pam_auth_userpass(array(‘username’ => $username, ‘password’ => $password)))

    and it will work fine.

    Comment by Amdizzle — February 19, 2009 @ 8:26 pm

  8. To output the results other than HTML (for example, JSON), add “view=json” to the call url.

    Comment by Ji — March 15, 2009 @ 7:24 pm

  9. Doesnt auth.gettoken does that returns the API key to authenticate the user with token based authentication???

    Comment by Jose Ayerdis — June 18, 2010 @ 2:14 am

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress