Sahana Eden

Web Services

Web Services in Sahana Eden are implemented as a RESTful API (Application Programming Interface).

This API allows other applications to access and manipulate Sahana Eden data resources directly over the web using the HTTP protocol, which means:

  • URLs to address resources
  • HTTP requests to perform actions and transfer data
  • HTTP method verbs (GET, PUT, POST, DELETE) to specify the actions to be performed
  • HTTP status codes to report status and errors

A powerful query language is available to address particular data elements:

/eden/pr/person?person.first_name__like=Miriam

(all person records where the first name contains "Miriam")

...or to specify method parameters:

/eden/org/office/analyze?col=location_id&row=type&fact=name&aggregate=group_concat

(a pivot table of offices grouped by facility type vs. location)

The RESTful API uses Sahana Eden's native S3XML format for data exchange. Other XML or JSON formats are supported using on-the-fly XSLT transformation - Sahana Eden provides built-in XSLT stylesheets for a variety of XML standards (e.g. KML, EDXL-HAVE), and can also accept custom stylesheets.

URL Format

Basic URL Syntax

Example of a URL to address a resource in the Sahana Eden RESTful API:

http://vita.sahanafoundation.org/eden/hms/hospital/1/bed_capacity/create

The basic URL format is:

(Parts in { } are optional, [ A | B ] indicates alternatives)

http:// server / path / prefix / name { /<arguments> }{ ?<query> }
  • server (vita.sahanafoundation.org) is the server domain name
  • path (/eden) the path to the application
  • prefix (/hms) is the name (prefix) of the Sahana Eden module
  • name (/hospital) is the resource name

The <arguments> list consists of:

{ /id }{ / [ method | component { /component_id } { /method } ] } {.format}
  • id (/1) is a record ID in the master table of the resource
  • component (/bed_capacity) is a component name
  • component_id is a record ID in the component
  • method (/create) is a method of the resource
  • format specifies the requested data format (e.g.: ".xml" for S3XML)

For the <query> syntax, see the following section.

Basic Query Format

Example of a URL query:

?hospital.name__like=Example%20Hospital

...as part the complete URL:

http://vita.sahanafoundation.org/eden/hms/hospital?hospital.name__like=Example%20Hospital
The basic query format is:
?resource.{foreign key$}field{operator}=value(s)
  • resource (hospital) is the name of the component, followed by a period (.)
  • foreign key is the name of the foreign key field followed by a dollar sign (to filter against a value in the table referenced by this foreign key)
  • field (name) is the name of the field in the target table
  • operator (__like) is the operator
  • value(s) (Example%20Hospital) is the value or a comma-separated list of values to test against (a comma will be treated as an OR)
Note that special characters in values must be properly URL-encoded (the %20 in this example stands for a blank).

Supported operators:

Operator Method Comments
__eq equal, = can be omitted
__ne not equal, !=
__lt less than, < numeric and date/time types only
__le less than or equal, <= numeric and date/time types only
__gt greater than, > numeric and date/time types only
__ge greater than or equal, >= numeric and date/time types only
__like wildcard comparison, LIKE(%value%) string/text types only
__unlike negative wildcard comparison, NOT LIKE(%value%) string/text types only
__in containment, contains(value) list types only
__ex negative containment, excludes(value) list types only

Other Queries

Boundary Box Queries

For resources with location references (e.g. Hospitals), you can use boundary box queries to select records. The general format of the query variable is:

?bbox=minLon,minLat,maxLon,maxLat

You can also specify the foreign key field name of the location reference the query relates to (e.g. in case there are multiple location references in that resource):

?bbox.FKFieldName=minLon,minLat,maxLon,maxLat

Examples:

/hms/hospital?bbox=123,13.5,124,13.7
/hms/hospital?bbox.location_id=123,13.5,124,13.7

URL Examples

Interactive (HTML) Format

All "person" records in the Person Registry module (pr):

http://localhost:8000/eden/pr/person 

Non-interactive Formats

All "person" records in the Person Registry module (pr), in other data formats:

http://localhost:8000/eden/pr/person.pdf
http://localhost:8000/eden/pr/person.rss
http://localhost:8000/eden/pr/person.xml

Record by ID

http://localhost:8000/eden/pr/person/1
http://localhost:8000/eden/pr/person/1.pfif
http://localhost:8000/eden/pr/person/1.xml

Record by UUID

http://localhost:8000/eden/pr/person?person.uuid= urn:uuid:839bab5a-a401-4be3-8616-27fbc1810ef4

URL Queries

http://localhost:8000/eden/pr/person?person.id=1,2,3

http://localhost:8000/eden/org/office?office.type=None,1,2&office.obsolete=False

http://localhost:8000/eden/org/office?office.modified_on__gt=20110926T10:00:00
Note that in URL queries, date/time values must be in UTC and use the ISO-8601 combined format YYYMMDDThh:mm:ss.

Standard Methods

Standard methods include:

  • interactive create, read, update and delete (CRUD) including list views
  • data export/import in various formats, including on-the-fly transformation

Note:

  • in XML and JSON, resources are always exported/imported including all their components and referenced resources.
  • in all other formats, the components need to be addressed separately

GET

Interactive Formats

Interactive formats are HTML (Extension ".html"), or PLAIN (Extension ".plain"). If no format extension is specified, HTML format is assumed.

  • without method specified in the URL:
    • if no record ID in the URL: list view of the resource
    • with a record ID in the URL: read view of the specified record (if the user is permitted to update the record, an update form returned instead)

Example: read view of the person record #1:

http://localhost:8000/eden/pr/person/1
  • with method specified in the URL:
    • method create returns a create-form
    • method read returns a view of the specified record (other than with blank method, no update form is returned in this case)
    • method update returns an update form for the specified record
    • method delete returns a delete confirmation form together with a list of the specified records (if there is exactly one record identified by its ID in the URL, then the record will be deleted instead of a form being returned, see POST)

Example: create form for a new person record:

http://localhost:8000/eden/pr/person/create
  • some resources support other methods, e.g.
    • search returns a search form for the resource

Example: search for a person by name or ID:

http://localhost:8000/eden/pr/person/search

Non-interactive formats

Any format extension that is not listed under the interactive formats, is treated as non-interactive.

  • without method in the URL:
    • returns all matching records in the specified format

Example: all person records the user is allowed to read, in S3XML format:

GET http://localhost:8000/eden/pr/person.xml
  • with method in the URL:
    • method create or update returns a schema document of the resource
    • method create or update together with a source imports the data into the specified resource (see chapter S3XML)
    • method options returns a field options document of the resource
    • other methods are not supported

Example: get a schema document of the person resource:

GET http://localhost:8000/eden/pr/person/create.xml
  • XLS and PDF formats work read-only (create/update/delete being ignored)

POST

Interactive Formats

  • performs the respective method (if specified in the request)
    • method create creates a new record
    • method update updates the specified record
    • method delete deletes the specified record
  • expects the form data as multi-part request body

Non-interactive Formats

  • enters an interactive review of the source data before importing the data into the resource

PUT

Interactive formats

  • see POST

Non-interactive formats

  • import data from the request body (which must be in the specified format) into the resource
  • records being matched by the UIDs specified in the data, while any record IDs in the URL restrict the selection

DELETE

  • deletes those of the addressed records which are deletable by the current user

Authorization

It is possible to access privileged resources by providing the username/password within each request, rather than the usual method of having the login stored within the session.

The RESTful API supports HTTP Basic Authentication (http://en.wikipedia.org/wiki/Basic_access_authentication).

Note: for some command-line tools like wget or RESTClient you might need to additionally activate an option for pre-emptive authentication (unsolicited sending of credentials). E.g. for wget, use the --auth-no-challenge option.

AJAX Examples

Here some examples how to add the HTTP Basic Authentication header to AJAX requests:

function make_base_auth(user, password) {
 var tok = user + ':' + pass;
 var hash = Base64.encode(tok);
 return 'Basic ' + hash;
}

var auth = make_basic_auth('username@example.com', 'password');
var url = 'http://host.domain/eden/controller/function?vars';

// RAW
request = new XMLHttpRequest();
request.setRequestHeader('Authorization', auth);
request.open('PUT', url, true); // async=true
request.send(bodyContent);

// ExtJS
Ext.Ajax.request({
    url : url,
    method : 'GET',
    headers : { Authorization : auth }
});

// jQuery
$.ajax({
    url : url,
    method : 'GET',
    beforeSend : function(req) {
        req.setRequestHeader('Authorization', auth);
    }
});

Error Handling

The HTTP status code in the response indicates the success or failure of a request:

Status Code Cause  Response Body
 200 OK Success results or JSON message
400 BAD REQUEST Syntax error or method not supported for the specified resource
JSON message
401 UNAUTHORIZED Authorization required Clear text error
403 FORBIDDEN Insufficient permissions Clear text error
404 NOT FOUND Non-existent Resource Clear text error
50x Unrecoverable internal error Ticket issued or clear text error
  Where a JSON message is returned, it has the following structure:
  {
    success= "True" | "False",
    statuscode = "XXX",
    message = "clear text error message",
    tree = {
      /* element tree */
    }
  }

If there was an input element tree and it contained any errors, a subtree with the invalid elements will be added to the JSON message ("tree"). This subtree is expressed in JSON Format. Invalid elements will have an additional @error attribute containing a clear-text error desription.

Skipping invalid records at import:

By default, an import request will be rolled back (completely) and an HTTP 400 BAD REQUEST error be returned if the source contains any invalid data.

You can override this behavior by using the ignore_errors URL variable (?ignore_errors=True). Invalid records will then be skipped, while the valid records will be committed to the database and the request returns a HTTP 200 OK. The JSON message in the response body would however contain the error message and the element tree with the invalid elements.

Note that ignore_errors applies to Validation Errors only. Any other type of error (e.g. XML syntax error) will be handled as usual (=rollback + error message).

The ignore_errors option is meant for "dirty" data, e.g. cases where you need to import from a source but do not have permission and/or means to clean it up before import. In all other cases, where possible, you should avoid ignore_errors and rather sanitize the source.

S3XML On-the-fly Transformation

The Sahana Eden RESTful API can perform XSLT transformation of XML sources into the S3XML format on-the-fly when exporting or importing data.

 


The XSLT stylesheets to use for this transformation can be:

  • a static file on the server or a web URL
  • a file attached to the request (at import)
  • an integrated stylesheet of Eden (folder static/formats)

Note:

  • You cannot use the .xml or .json extension if the source is to be transformed. By these extensions, the interface assumes the source is already S3XML.
  • Non-XML formats such as PDF or XLS do not support on-the-fly transformation.

Integrated Transformation Stylesheets

Sahana Eden provides a number of internal XSLT stylesheets for various formats. These will be automatically used if no other stylesheet is specified (fallback). The internal stylesheets reside in:

  • static/formats/<format>/export.xsl to transform S3XML into another format
  • static/formats/<format>/import.xsl to transform another format into S3XML

Example:

  • static/formats/have/import.xsl transforms EDXL-HAVE (*.have) into S3XML
  • static/formats/have/export.xsl transforms S3XML into EDXL-HAVE

XSLT Stylesheets on the Server

You can use the URL variable transform to specify a transformation stylesheet at a file system location on the server, e.g.:

http://127.0.0.1:8000/eden/pr/person.pfif?transform=/home/dominic/stylesheets/pfif.xsl

...or at another location on the web,e.g.:

http://127.0.0.1:8000/eden/pr/person.rss?transform=http://pub.nursix.org/eden/formats/rss.xsl

If you use transform to specify the stylesheet location explicitly, any existing internal stylesheet for the format extension would not be used.

Note:

  • the Eden web server must be permitted to access the stylesheet without authentication
  • the request must not use ".xml" as data format extension, otherwise no transformation will be performed at all (transform would be ignored then)

This feature is especially useful to create custom feeds to integrate into remote sites, e.g. RSS:

  • create your own rss.xsl to transform S3XML into RSS
  • place it on a public (e.g. your own) web server, e.g.:
http://www.example.org/eden-access/rss.xsl
  • provide a feed link to Eden resources using your RSS stylesheet:
    http://edensite.org/eden/hms/hospital.rss?transform=http://www.mysite.org/eden-access/rss.xsl
    

This does work with any XML format, e.g. KML - if you wanted to provide a map rather than a feed link.

Attached XSLT Stylesheets

For data import, an XSLT stylesheet to transform foreign XML into S3XML can be attached to the request.

The filename of the attached stylesheet is expected to be <resourcename>.xsl, where <resourcename> is the name of the target resource (without module prefix, e.g. person or hospital).

Note:

  • document(), xsl:include and xsl:import will need absolute paths in this case (safer to avoid these)