This post will show how it can be simple to create an hybrid mobile app using HTML, CCS and Javascript (i.e. a Phonegap app), and jBackend to access to Joomla content in JSON format and so to use Joomla as data source to feed the app. It's easy as 1,2,3.

jBackend Demo App

Published in Newsblog
Friday, 27 June 2014 00:00

Changelog

Version 3.8.0:

  • Fixed an issue with create notifications for devices;
  • [plg_jbackend_content] added function to get an article by alias;
  • [plg_jbackend_content] dropped unpublished articles in get articles by tag;
  • [plg_jbackend_user] fixed an issue with FieldsHelper;
  • [plg_jbackend_push] replaced GCM with FCM.

Version 3.7.0:

  • Added license integration with jBackend Release System.

Version 3.6.0:

  • Fixed an issue with API key usage;
  • Fixed an issue with session_id;
  • Now all dates in DATETIME format are UTC-based;
  • [plg_jbackend_content] output date format changed to ISO 8601;
  • [plg_jbackend_content] added max limit option;
  • [plg_jbackend_user] fixed profile extra fields.

Version 3.5.0:

  • [plg_jbackend_content] extended support for joomla custom fields to the article list.

Version 3.4.0:

  • Added the list of endpoints on the dashboard;
  • [plg_jbackend_content] added support for joomla custom fields.

Version 3.3.0:

  • Added a log of all notifications sent;
  • Added target devices to push notifications;
  • [plg_jbackend_push] fixed an issue with NOW;
  • [plg_jbackend_content] fixed an issue with function to get articles by tags.

Version 3.2.0:

  • Improved CORS support;
  • Added delete all logs button;
  • Added endpoint filtering to logs;
  • Added target endpoints feature for API keys;
  • Added the user information to a registered device;
  • Added support for api_key passed as Authorization header (Authorization: api_key );
  • Added support for api_key passed as JSON parameter;
  • Added target users and groups to push notifications;
  • [plg_jbackend_user] fixed an issue with registration, remind and reset when captcha is enabled;
  • [plg_jbackend_user] added an option to process register, remind and reset as an authentication request;
  • [plg_jbackend_content] added an option to return also raw content (no content plugin);
  • [plg_jbackend_push] added an API function to create a push notification.

Version 3.1.0:

  • Added support for session_id passed as GET/POST/JSON parameter;
  • Added support for custom payload in push notifications;
  • Fixed an issue with log search.

Version 3.0.0:

  • Added support for push notifications for iOS and Android;
  • Added user information to logs;
  • Improved logs filtering;
  • Added CSV export to logs;
  • [plg_jbackend_content] added hits to single article response;
  • [plg_jbackend_content] added an option to exclude content from article list;
  • [plg_jbackend_content] added an option to include support for SEBLOD CCK custom fields;
  • [plg_jbackend_user] added profile request;
  • [plg_jbackend_user] added profile update request;
  • [plg_jbackend_user] added status request.

Version 2.1.3:

  • [plg_jbackend_user] fixed a PHP 5.3 compatibility issue (array initialization).

Version 2.1.2:

  • Added basic CORS feature;
  • [plg_jbackend_user] added username remind request;
  • [plg_jbackend_user] added password reset request.

Version 2.1.1 (only for J3):

  • Added the force SSL option.

Version 2.1.0:

  • Fixed an issue with delete log entry;
  • Fixed an issue with installer script;
  • Added the ability to select which modules to enable for each endpoint.

Version 2.0.2:

  • Fixed an issue with API key expiration check related to never expiring keys;
  • [plg_jbackend_content] added filter by featured in the list of articles;
  • [plg_jbackend_content] added featured field in the response for the list of articles;
  • [plg_jbackend_content] added tags to response for articles (only for J3);
  • [plg_jbackend_content] added tagarticles resource to get articles by tag (only for J3).

Version 2.0.1:

  • Added onBeforeCheckModule event.

Version 2.0.0:

  • Added a trace function for logs and statistics;
  • Added a new dashboard as a better landing page;
  • [plg_jbackend_content] fixed an issue with generateImagesFields() function;
  • [plg_jbackend_content] added a plugin option to force full image URLs in content.

Version 1.0.3:

  • [plg_jbackend_user] fixed an issue with com_users language costants.

Version 1.0.2:

  • [plg_jbackend_content] fixed an issue with orderby and orderdir parameters;
  • [plg_jbackend_content] added images fields for a single article and the list of articles;
  • [plg_jbackend_content] added a plugin option to return relative or full URLs for images fields;
  • [plg_jbackend_content] changed the date format of published date to YYYY-MM-DD HH:MM:SS.

Version 1.0.1:

  • Completed porting to J2
  • Some minor fixes and little improvements

Version 1.0.0:

  • Initial J3 version

Menu module

Version 1.0.1:

  • Fixed an issue with get menu items due to a new ACL check.

Version 1.0.0:

  • Initial version.

K2 module

Version 1.3.1:

  • Fixed an issue with ordering parameter in items.

Version 1.3.0:

  • Added support for language filter on categories and items;
  • Added an option to force full url for all img tags;
  • Improved support for K2 plugins in the list of items.

Version 1.2.0:

  • Added an option to include or exclude full content from items response;
  • Added introtext to item and items response;
  • Added extra_fields and extra_fields_search to item and items response;
  • Added image field to category and categories response;
  • Fixed an issue with items ordering.

Version 1.1.1:

  • Fixed an issue with path of images.

Version 1.1.0 (only for J3):

  • Fixed an issue with list of items.

Version 1.0.4 (only for J2):

  • Fixed an issue with path of images.

Version 1.0.3:

  • Some code optimization.

Version 1.0.2:

  • Fixed name of plugin options constants;
  • Changed error code K2_KGE to K2_CGE.

Version 1.0.1:

  • Completed porting to J2;
  • Some minor fixes and little improvements.

Version 1.0.0:

  • Initial J3 version.

SobiPro module

Version 1.2.0:

  • Added category_name filter field for entries;
  • Added an option to enable JSON payload on entries action.

Version 1.1.0:

  • Changed entries function to support multiple categories.

Version 1.0.1:

  • Some code optimization.

Version 1.0.0:

  • Initial version.

ZOO module

Version 1.1.1:

  • Extended named elements also for a single item (thanks to Ray Lawlor).

Version 1.1.0:

  • Added an option to include elements in the list of items (thanks to Ray Lawlor);
  • Added an option to use slug (friendly) names for elements (thanks to Ray Lawlor).

Version 1.0.0:

  • Initial version.

Kunena module

Version 1.0.0:

  • Initial version.

Community Builder module

Version 1.0.1:

  • Added full URL for avatar field in the get user profile.

Version 1.0.0:

  • Initial version.
Tuesday, 10 June 2014 00:00

Developer's guide

jBackend provides a robust and extensible solution to expose content and services through a Joomla website. The component provides the basic structure that has in charge of managing requests, controlling accesses, and dispatching incoming requests to the corresponding module. The jBackend architecture is extensible because its service modules are implemented as Joomla plugins, so adding new plugins allows to add new services and expose the contents of new extensions.

In this section we will describe how to create custom modules, and what is the structure of a jBackend plugin. For this purpose it was created an "Hello World" plugin available for download here:

http://www.selfget.com/downloads/file/31-plg-jbackend-helloworld-j30.html

Structure of supported requests

Each HTTP request to an jBackend endpoint MUST include at least three parameters:

action=<action_type>
module=<module_name>
resource=<service_request>

The action would specify one of the HTTP methods used in a RESTful service (e.g. GET, PUT, POST, or DELETE). This is because all Joomla requests are made using GET, so this FIRST parameter introduces the missing information.

The module parameter indicates the name of the module that has in charge of managing this request (e.g. content). This can be implemented as a single jBackend plugin, or even a pool of plugins where each one implements a subset of module services. As example, for com_content core extension a content plugin already exists, which provides read-only access to content and categories. It could be possible to create a new plugin (e.g. plg_jbackend_content_admin) registered also as content module, which takes in charge editor functions like create content and categories.

The resource parameter specifies the service we are requesting to the module (e.g. articles of the content module, login service of the user module, etc.). This parameter must be validated and managed by the plugin itself, no checks will be made on this by jBackend (it cannot know about services provided by each plugin).

Considering all the required parameters (action, module, and resource), each request has this structure:

<end-point>?action=<action_type>&module=<module_name>&resource=<service_request>

If Joomla SEF is enabled, the request can assume this REST-like structure:

<end-point>/<action_type>/<module_name>/<service_request>

A request can also take additional parameters needed by the resource itself for the required service (e.g. the id of the article). This parameters can be added as a standard URL query string, so the request structure assumes this aspect:

<end-point>?action=<action_type>&module=<module_name>&resource=<service_request>&var1=<value1>&...&varN=<valueN>

Or can be (when SEF is enabled):

<end-point>/<action_type>/<module_name>/<service_request>?var1=<value1>&...&varN=<valueN>

An event onBeforeCheckModule is triggered just before to check the module name to dispatch. This permits to override the module variable (as well as action and resource variables) before the request dispatching process and can be useful, as example, when a plugin must deal with existing client requests that cannot be customized as required by jBackend.

Using onBeforeCheckModule it is possible, as example, to match a request like the following:

<endpoint>?var=catchme

This request doesn't include any of the required variables (action, module, resource), but we can "catch" the var and set the required variables:

  public function onBeforeCheckModule()
  {
    $app = JFactory::getApplication();
    $var = $app->input->getString('var');
    if ($var === 'catchme') {
      $app->input->set('action', 'get');
      $app->input->set('module', 'content');
      $app->input->set('resource', 'articles');
      $app->input->set('catid', '64');
      $app->input->set('id', '71');
    }
  }

Basic elements of a jBackend plugin

As a standard Joomla plugin, any jBackend plugin needs an XML installation file with the following structure:

<?xml version="1.0" encoding="utf-8"?>
<extension version="3.0" type="plugin" group="jbackend" method="upgrade">
    <name>plg_jbackend_helloworld</name>
...
</extension>

The plugin group must be "jbackend". All other XML elements are the same of a standard Joomla plugin. The PHP plugin code should have a generateError() function which builds and return all plugin specific errors:

  /**
   * This is the function to generate plugin specific errors
   * The error response is an array with the following structure:
   *    array(
   *     'status' => 'ko',
   *     'error_code' => $errorCode,
   *     'error_description' => <short error description>
   *    )
   *
   * @param  string  $errorCode  The error code to generate
   *
   * @return  array  The response of type error to return
   */
  public static function generateError($errorCode)
  {
    $error = array();
    $error['status'] = 'ko';
    switch($errorCode) {
      case 'REQ_ANS':
        $error['error_code'] = 'REQ_ANS';
        $error['error_description'] = 'Action not specified';
        break;
      case 'HWD_GEN':
        $error['error_code'] = 'HWD_GEN';
        $error['error_description'] = 'Generic hello world error';
        break;
    }
    return $error;
  }

It is not mandatory, but a good practice for the format of the error code is to use a pattern like XXX_YYY, where XXX is a code associated to the plugin (e.g. HWD for the helloworld plugin), and YYY for the specific error (e.g. GEN for generic error).

The other function that any jBackend plugin should have is the onRequest<Module>() function. This is called by jBackend during requests dispatching process. It has three parameters, an input parameter $module that is the module name and is used by the plugin to understand if it should handle the request, an output parameter $response that is the response object, and a $status parameter that can return additional information. The function returns true if there are no problems (status = ok), false in case of errors (status = ko):

public function onRequestHelloWorld($module, &$response, &$status = null)

The first thing the onRequest function should do is to check if it must handle the request or not. If not, it should return to improve the performance of the dispatching process:

if ($module !== 'helloworld') return true; // Check if this is the triggered module or exit

The second thing is to add the plugin to the module call stack:

// Add to module call stack
jBackendHelper::moduleStack($status, 'helloworld'); // Add this request to the module stack register

After these tasks, it is possible to get request vars and process the response:

$app = JFactory::getApplication();
$action = $app->input->getString('action');
$resource = $app->input->getString('resource');

// Check if the action is specified
if (is_null($action)) {
  $response = plgJBackendHelloWorld::generateError('REQ_ANS'); // Action not specified
  return false;
}

switch ($resource)
{
  case 'greeting':
    if ($action == 'get')
    {
      return $this->actionGreeting($response, $status);
    }
    break;
  case 'about':
    if ($action == 'get')
    {
      return $this->actionAbout($response, $status);
    }
    break;
}

return true;

Each function like actionGreeting() and actionAbout() is specific to manage the resource requested by the action. To maintain the code clean it is a good practice to create a different function for each action.

The following is an example of an action() function that shows the code structure and how to manage the errors:

  public function actionGreeting(&$response, &$status = null)
  {
    $app = JFactory::getApplication();

    // Get additional request parameters
    $id = $app->input->getInt('id');
    if (!is_null($id))
    {
      // Example of how to generate and return an error inside an action function
      if ($id == '101')
      {
        $response = plgJBackendHelloWorld::generateError('HWD_GEN'); // Generic hello world error
        return false;
      }
    }

    // Get plugin params
    $option_name = $this->params->get('option_name', 0);

    $response['status'] = 'ok';
    $response['message'] = $this->_greeting_msg;
    if ($option_name)
    {
      $response['option'] = 'true';
    }
    return true;
  }
Saturday, 19 April 2014 00:00

Content Module API

The Content Module is implemented with the plg_jbackend_content plugin. It provides functions related to Joomla content (articles and categories). Here is the list of supported methods.

Get the list of categories

Request parameters

action=get
module=content
resource=categories
rootid=<R> (optional)
recursive=<true or 1> (optional)
countitems=<true or 1> (optional)

Example

<end-point>?action=get&module=content&resource=categories&rootid=<R>&recursive=<false>&countitems=<0>

Example (REST format)

<end-point>/get/content/categories?rootid=<R>

Response

{
    "status": "ok",
    "total": <T>,
    "categories": [
        {
            "id": "<category id>",
            "title": "<category title>",
            "description": "<category description>",
            "parent_id": "<parent category id>",
            "numitems": <items count>
        },
        ...
        {
            "id": "<category id>",
            "title": "<category title>",
            "description": "<category description>",
            "parent_id": "<parent category id>",
            "numitems": <items count>
        }
    ]
}

Notes

If rootid is specified, starts to get subcategories from the specified category id instead of the root category. If recursive is true or 1, get categories and all subcategories, otherwise get only one level (default). If countitems is true or 1, return the number of articles of each category, otherwise do not return this information (default). Category id can be "root" for root node.

 

Get a category

Request parameters

action=get
module=content
resource=categories
id=<N>

Example

<end-point>?action=get&module=content&resource=categories&id=<N>

Example (REST format)

<end-point>/get/content/categories/<N>

Response

{
    "status": "ok",
    "id": "<category id>",
    "title": "<category title>",
    "alias": "<category alias>",
    "description": "<category description>",
    "metadesc": "<meta description>",
    "metakey": "<meta keywords>",
    "metadata": {
        "page_title": "<meta title>",
        "author": "<meta author>",
        "robots": "<meta robots>"
    },
    "language": "<language code>",
    "parent_id": "<category id>",
    "level": "<category level>",
    "numitems": "<N>"
}

Notes

Language can be "*" if any. Category id can be "root" for root node.

 

Get the list of articles

Request parameters

action=get
module=content
resource=articles
catid=<C> (optional)
maxsubs=<S> (optional)
featured=<F> (optional)
limit=<L> (optional)
offset=<O> (optional)
orderby=<field> (optional)
orderdir=<dir> (optional)

Example

<end-point>?action=get&module=content&resource=articles&catid=<C>&maxsubs=<S>&featured=<F>&orderby=<id>

Example (REST format)

<end-point>/get/content/articles?catid=<C>&limit=<L>&offset=<O>

Response

{
    "status": "ok",
    "total": <total articles>,
    "limit": <pagination limit>,
    "offset": <pagination offset>,
    "pages_current": <current page>,
    "pages_total": <total pages>,
    "articles": [
        {
            "id": "<article id>",
            "title": "<article title>",
            "alias": "<article alias>",
            "featured": "<featured>",
            "content": "<article content>",
            "catid": "<article category id>",
            "images": {
                "image_intro": "<image_url_for_intro>",
                "float_intro": "<float_side_for_intro>",
                "image_intro_alt": "<alt_text_for_intro>",
                "image_intro_caption": "<caption_for_intro>",
                "image_fulltext": "<image_url_for_fulltext>",
                "float_fulltext": "<float_side_for_fulltext>",
                "image_fulltext_alt": "<alt_text_for_fulltext>",
                "image_fulltext_caption": "<caption_for_fulltext>"
            },
            "tags": [
                {
                    "id": "<tag id>",
                    "title": "<tag title>",
                    "alias": "<tag alias>",
                    "language": "<tag language>"
                },
                ...
            ],
            "fields": [
                {
                    "id": "<field id>",
                    "title": "<field title>",
                    "name": "<field name>",
                    "type": "<field type>",
                    "default_value": "<default value>",
                    "group_id": "<field group id>",
                    "label": "<field label>",
                    "description": "<field description>",
                    "required": "<field required>",
                    "value": "<field value>",
                    "rawvalue": "<field raw value>"
                },
                ...
            ],
            "metakey": "<meta keywords>",
            "metadesc": "<meta description>",
            "metadata": {
                "robots": "<meta robots>",
                "author": "<meta author>",
                "rights": "<meta content rights>",
                "xreference": "<meta external reference>"
            },
            "language": "<language code>",
            "category_title": "<category title>",
            "category_alias": "<category alias>",
            "author": "<article author>",
            "created_date": "<created date>",
            "modified_date": "<modified date>",
            "published_date": "<publish up date>",
            "unpublished_date": "<publish down date>",
            "state": "<article state>"
            },
            ...
            {
                ...
            }
    ]
}

Notes

State:

  • Published = 1,
  • Unpublished = 0,
  • Archived = 2,
  • Trashed = -2

Max subs:
Number of subcategories to include (default 0=none)

Featured:
hide,only,show (default)

Order by:
id, title, alias, catid, state, created, created_by, ordering (default), hits

Order dir:
asc (default), desc

Dates are in ISO 8601 format (e.g 2017-05-11T10:16:32+00:00)

Property content is present only if plugin's option Content in article list is set.

Property tags is present only if plugin's option Add tags in article list is set.

Property fields is present only if plugin's option Prepare content in article list is set.

 

Get an article

Request parameters

action=get
module=content
resource=articles
id=<N>

Example

<end-point>?action=get&module=content&resource=articles&id=<N>

Example (REST format)

<end-point>/get/content/articles/<N>

Response

{
    "status": "ok",
    "id": "<article id>",
    "title": "<article title>",
    "alias": "<article alias>",
    "featured": "<featured>",
    "introtext": "<article intro text>",
    "content": "<article content>",
    "content_raw": "<article content raw>",
    "catid": "<article category id>",
    "images": {
        "image_intro": "<image_url_for_intro>",
        "float_intro": "<float_side_for_intro>",
        "image_intro_alt": "<alt_text_for_intro>",
        "image_intro_caption": "<caption_for_intro>",
        "image_fulltext": "<image_url_for_fulltext>",
        "float_fulltext": "<float_side_for_fulltext>",
        "image_fulltext_alt": "<alt_text_for_fulltext>",
        "image_fulltext_caption": "<caption_for_fulltext>"
    },
    "tags": [
        {
            "id": "<tag id>",
            "title": "<tag title>",
            "alias": "<tag alias>",
            "language": "<tag language>"
        },
        ...
    ],
    "associations": [
    ],
    "event": {
        "afterDisplayTitle": "<after display title>",
        "beforeDisplayContent": "<before display content>",
        "afterDisplayContent": "<after display content>"
    },
    "fields": [
        {
            "id": "<field id>",
            "title": "<field title>",
            "name": "<field name>",
            "type": "<field type>",
            "default_value": "<default value>",
            "group_id": "<field group id>",
            "label": "<field label>",
            "description": "<field description>",
            "required": "<field required>",
            "value": "<field value>",
            "rawvalue": "<field raw value>"
        },
        ...
    ],
    "cck_fields": [
    ],
    "metakey": "<meta keywords>",
    "metadesc": "<meta description>",
    "metadata": {
        "robots": "<meta robots>",
        "author": "<meta author>",
        "rights": "<meta content rights>",
        "xreference": "<meta external reference>"
    },
    "language": "<language code>",
    "category_title": "<category title>",
    "category_alias": "<category alias>",
    "author": "<article author>",
    "parent_id": "<parent id>",
    "parent_title": "<parent title>",
    "parent_alias": "<parent alias>",
    "parent_route": "<parent route>",
    "created_date": "<created date>",
    "modified_date": "<modified date>",
    "published_date": "<publish up date>",
    "unpublished_date": "<publish down date>",
    "version": "<article version>",
    "hits": "<article hits>",
    "rating": "<article rating>",
    "rating_count": "<article rating count>",
    "state": "<article state>"
}

Notes

State:

  • Published = 1,
  • Unpublished = 0,
  • Archived = 2,
  • Trashed = -2

Dates are in ISO 8601 format (e.g 2017-05-11T10:16:32+00:00)

Language can be "*" if any.

Property content_raw is present only if plugin's option Include content raw is set.

Property event is present only if plugin's option Show article event is set.

Property cck_fields is present only if plugin's option Include CCK is set.

 

Get the list of articles by tag id

Request parameters

action=get
module=content
resource=tagarticles
tagid=<T1,T2,...,Tn>
limit=<L> (optional)
offset=<O> (optional)

Example

<end-point>?action=get&module=content&resource=tagarticles&tagid=<T>&limit=<L>&offset=<O>

Example (REST format)

<end-point>/get/content/tagarticles?tagid=<T>&limit=<L>&offset=<O>

Response

{
    "status": "ok",
    "total": <total articles>,
    "limit": <pagination limit>,
    "offset": <pagination offset>,
    "pages_current": <current page>,
    "pages_total": <total pages>,
    articles: [
        {
            "id": "<article id>",
            "title": "<article title>",
            "alias": "<article alias>",
            "featured": "<featured>",
            "content": "<article content>",
            "images": {
                "image_intro": "<image_url_for_intro>",
                "float_intro": "<float_side_for_intro>",
                "image_intro_alt": "<alt_text_for_intro>",
                "image_intro_caption": "<caption_for_intro>",
                "image_fulltext": "<image_url_for_fulltext>",
                "float_fulltext": "<float_side_for_fulltext>",
                "image_fulltext_alt": "<alt_text_for_fulltext>",
                "image_fulltext_caption": "<caption_for_fulltext>"
            },
            "tags": [
                {
                    "id": "<tag id>",
                    "title": "<tag title>",
                    "alias": "<tag alias>",
                    "language": "<tag language>"
                },
                ...
            ],
            "metadesc": "<meta description>",
            "metakey": "<meta keywords>",
            "metadata": {
                "robots": "<meta robots>",
                "author": "<meta author>",
                "rights": "<meta content rights>",
                "xreference": "<meta external reference>"
            },
        "category_title": "<category title>",
        "author": "<article author>",
        "published_date": "<article date>"
        },
        ...
        {
            ...
        }
    ]
}

Notes

Dates are in ISO 8601 format (e.g 2017-05-11T10:16:32+00:00)

 

Get an article by alias

Request parameters

action=get
module=content
resource=articlebyalias
id=<alias>

Example

<end-point>?action=get&module=content&resource=articlebyalias&id=<alias>

Example (REST format)

<end-point>/get/content/articlebyalias/<alias>

Response

Same response as "Get an article"

Notes

Same notes as "Get an article".

 

Plugin Settings

jBackend Content Plugin Settings

The following options are available for user plugin:

Option Description
Filter language Filter content by language.
Status Filter content by state.
Access archived articles Allow get article on archived items.
Grant access Skip access permissions check and allow access to articles.
Full image URL Generate absolute URL (i.e. with domain) for images fields.
Force full image URL in content Try to replace relative image URL in content with absolute URL.
Add tags in article list Include article tags in the list of articles.
Prepare content in article list Call onContent events on each article in the list of articles.
Content in article list Include full content in the list of articles.
Show article event Include results of events in the article response.
Include content raw Include raw content (no content plugin) in the article response.
Include CCK Include SEBLOD CCK custom fields in the article response.
Saturday, 19 April 2014 00:00

User Module API

The User Module is implemented with the plg_jbackend_user plugin. It provides functions related to Joomla users and ACL. Here is the list of supported methods.

User login

Request parameters

action=post
module=user
resource=login
username=<username>
password=<password>

Example

<end-point>?action=post&module=user&resource=login&username=<username>&password=<password>

Example (REST format)

<end-point>/post/user/login?username=<username>&password=<password>

Response

{
    "status": "ok",
    "userid": <userid>,
    "username": "<username>",
    "session_id": "<session_id>"
}

 

To avoid to pass credentials in clear it is recommended to expose the endpoint over HTTPS, and to pass username and password as POST variables (it is supported out-of-the-box), or enabling JSON Login option and using a POST method with a JSON payload.

 

User logout

Request parameters

action=get
module=user
resource=logout

Example

<end-point>?action=get&module=user&resource=logout

Example (REST format)

<end-point>/get/user/logout

Response

{
    "status": "ok"
}

 

User registration

Request parameters

action=post
module=user
resource=register
username=<username>
password=<password>
email=<email>
firstname=<firstname>
lastname=<lastname>

Example

<end-point>?action=post&module=user&resource=register&username=<username>&password=<password>&email=<email>&firstname=<firstname>&lastname=<lastname>

Example (REST format)

<end-point>/post/user/register?username=<username>&password=<password>&email=<email>&firstname=<firstname>&lastname=<lastname>

Response

{
    "status": "ok"
}

 

To avoid to pass sensible data in clear it is recommended to expose the endpoint over HTTPS, and to pass variables using POST method (it is supported out-of-the-box), or enabling JSON Register option and using a POST method with a JSON payload.

 

User remind

Sends an email to the user's account with a password remind link.

Request parameters

action=get
module=user
resource=remind
email=<email>

Example

<end-point>?action=get&module=user&resource=remind

Example (REST format)

<end-point>/get/user/remind

Response

{
    "status": "ok"
}

 

User reset

Sends an email to the user's account with a password reset link.

Request parameters

action=get
module=user
resource=reset
email=<email>

Example

<end-point>?action=get&module=user&resource=reset

Example (REST format)

<end-point>/get/user/reset

Response

{
    "status": "ok"
}

 

User profile

Request parameters

action=get
module=user
resource=profile

Example

<end-point>?action=get&module=user&resource=profile

Example (REST format)

<end-point>/get/user/profile

Response

{
    "status": "ok",
    "fields": [
        {
            "id": "<id>",
            "title": "<title>",
            "name": "<name>",
            "language": "<language>",
            "type": "<type>",
            "default_value": "<default value>",
            "context": "<context>",
            "group_id": "<group id>",
            "label": "<label>",
            "description": "<description>",
            "required": "<required>",
            "language_title": "<language title>",
            "language_image": "<language image>",
            "group_title": "<group title>",
            "value": "<value>",
            "rawvalue": "<raw value>"
        },
        ...
    ],
    "_errors": [<_errors>],
    "groups": {
        "<groupid>": "<groupid>"
        ...
    },
    "id": "<id>",
    "name": "<name>",
    "username": "<username>",
    "email": "<email>",
    "block": "<block>",
    "sendEmail": "<sendEmail>",
    "registerDate": "<registerDate>",
    "lastvisitDate": "<lastvisitDate>",
    "activation": "<activation>",
    "params": {
        "admin_style": "<admin_style>",
        "admin_language": "<admin_language>",
        "language": "<language>",
        "editor": "<editor>",
        "helpsite": "<helpsite>",
        "timezone": "<timezone>"
    },
    "lastResetTime": "<lastResetTime>",
    "resetCount": "<resetCount>",
    "otpKey": "<otpKey>",
    "otep": "<otep>",
    "requireReset": "<requireReset>",
    "tags": {
        "typeAlias": <typeAlias>,
        "tags": "<tags>"
    }
}

 

It is possible to filter fields in the response just specifying the field list in the Required fields option.

 

User profile update

Allows to update the user profile (user must be authenticated). The requests must use the POST method with a JSON payload.

Request parameters

action=put
module=user
resource=profile

Example

POST <end-point>?action=put&module=user&resource=profile

Example (REST format)

POST <end-point>/put/user/profile

JSON payload data:

{
    "name": "<name>",
    "username": "<username>",
    "password": "<password>",
    "email": "<email>",
    "profile": {
        "city": "<city>"
        ...
    },
    "com_fields": {
        "field-1": "<value 1>",
        "field-2": "<value 2>"
        ...
    }
}

Response

{
    "status": "ok"
}

 

It is possible to specify any supported field in the payload, but the following fields are mandatory for each request: name, username, password, email

 

User status

Allows to check the current status of the user (guest or logged in), and provides some additional information.

Request parameters

action=get
module=user
resource=status

Example

<end-point>?action=get&module=user&resource=status

Example (REST format)

<end-point>/get/user/status

Response

{
    "status": "ok",
    "is_guest": <0 or 1>,
    "user_id": "<user_id>",
    "session_id": "<session_id>",
    "session_expire": <session_expire>
}

 

Plugin Settings

jBackend User Plugin Settings

The following options are available for user plugin:

Option Description
Auto activate Automatically activate users on registration and skip any notification email.
Extended auth request Process register, remind and reset as an authentication request (i.e. these requests can bypass the access restrictions on the endpoint).
Extended fields Enable support for additional fields in the registration.
External libraries List of paths (relative to JPATH_SITE) of external libraries to load in the registration (one path each row).
Required fields List of fields to include in the response for profile requests (when blank it returns all fields). Fields must be separated by commas and square brackets for nested fields (e.g. id,name,username,profile[city,region,country]).
JSON Login Enable JSON payload on login action.
JSON Register Enable JSON payload on register action.
Enable session id When enabled it overrides cookie based session with session_id parameter. This is useful when it is not possible to rely on cookie based session. This parameter can be passed as GET/POST param or as JSON field when JSON payload is enabled for the current request.
Friday, 18 April 2014 00:00

Error Codes

The general format for any error response is the following:

{
    "status": "ko",
    "error_code": "<code>",
    "error_description": "<description>"
}

 

The following table includes all error codes with description, grouped by "realm".

KNN_KNIKunena not installed{"status":"ko","error_code":"KNN_KNI","error_description":"Kunena not installed"}

Realm Error code Error description JSON format
Module related error codes REQ_ANS Action not specified {"status":"ko","error_code":"REQ_ANS","error_description":"Action not specified"}
REQ_MNS Module not specified {"status":"ko","error_code":"REQ_MNS","error_description":"Module not specified"}
REQ_MNF Module not found {"status":"ko","error_code":"REQ_MNF","error_description":"Module not found"}
REQ_RUN Request unknown {"status":"ko","error_code":"REQ_RNS","error_description":"Request unknown"}
API key related error codes REQ_AKR API key required {"status":"ko","error_code":"REQ_AKR","error_description":"API key required"}
REQ_AKL API key limit exceeded {"status":"ko","error_code":"REQ_AKL","error_description":"API key limit exceeded"}
REQ_AKE API key expired {"status":"ko","error_code":"REQ_AKE","error_description":"API key expired"}
REQ_AKI API key invalid {"status":"ko","error_code":"REQ_AKI","error_description":"API key invalid"}
REQ_AKG API key generic error {"status":"ko","error_code":"REQ_AKG","error_description":"API key generic error"}
User authentication related error codes REQ_UCA Unable to check authentication {"status":"ko","error_code":"REQ_UCA","error_description":"Unable to check authentication"}
REQ_AUR Authentication required {"status":"ko","error_code":"REQ_AUR","error_description":"Authentication required"}
User module USR_LIF Login failed {"status":"ko","error_code":"USR_LIF","error_description":"Login failed"}
USR_LOF Logout failed {"status":"ko","error_code":"USR_LOF","error_description":"Logout failed"}
USR_UNR Username required {"status":"ko","error_code":"USR_UNR","error_description":"Username required"}
USR_PWR Password required {"status":"ko","error_code":"USR_PWR","error_description":"Password required"}
USR_EMR Email required {"status":"ko","error_code":"USR_EMR","error_description":"Email required"}
USR_NMR Name required {"status":"ko","error_code":"USR_NMR","error_description":"Name required"}
USR_ALI Already logged in {"status":"ko","error_code":"USR_NMR","error_description":"Already logged in"}
USR_UNE User not enabled {"status":"ko","error_code":"USR_UNE","error_description":"User not enabled"}
USR_RNA Registration not allowed {"status":"ko","error_code":"USR_RNA","error_description":"Registration not allowed"}
USR_IRF Invalid registration field {"status":"ko","error_code":"USR_IRF","error_description":"Invalid registration field"}
USR_UNL User not logged in {"status":"ko","error_code":"USR_UNL","error_description":"User not logged in"}
USR_UNE User not enabled {"status":"ko","error_code":"USR_UNE","error_description":"User not enabled"}
USR_EDR Error during registration {"status":"ko","error_code":"USR_EDR","error_description":"Error during registration"}
USR_UAX Username already exists {"status":"ko","error_code":"USR_UAX","error_description":"Username already exists"}
USR_EAX Email already exists {"status":"ko","error_code":"USR_EAX","error_description":"Email already exists"}
USR_RRE Reset request error {"status":"ko","error_code":"USR_RRE","error_description":"Reset request error"}
USR_RRF Reset request failed {"status":"ko","error_code":"USR_RRF","error_description":"Reset request failed"}
Content module CNT_ANF Article not found {"status":"ko","error_code":"CNT_ANF","error_description":"Article not found"}
CNT_AGE Article generic error {"status":"ko","error_code":"CNT_AGE","error_description":"Article generic error"}
CNT_ANA Access not authorized {"status":"ko","error_code":"CNT_ANA","error_description":"Access not authorized"}
CNT_CNF Category not found {"status":"ko","error_code":"CNT_CNF","error_description":"Category not found"}
CNT_NCF No categories found {"status":"ko","error_code":"CNT_NCF","error_description":"No categories found"}
CNT_TNS Tag not specified {"status":"ko","error_code":"CNT_TNS","error_description":"Tag not specified"}
CNT_TGE Tag generic error {"status":"ko","error_code":"CNT_TGE","error_description":"Tag generic error"}
CNT_ANS Alias not specified {"status":"ko","error_code":"CNT_ANS","error_description":"Alias not specified"}
Push module PSH_TNS Token not specified {"status":"ko","error_code":"PSH_TNS","error_description":"Token not specified"}
PSH_ANS App code not specified {"status":"ko","error_code":"PSH_ANS","error_description":"App code not specified"}
PSH_PNS Platform not specified {"status":"ko","error_code":"PSH_PNS","error_description":"Platform not specified"}
PSH_PUN Platform unknown {"status":"ko","error_code":"PSH_PUN","error_description":"Platform unknown"}
PSH_ESA Error saving app code {"status":"ko","error_code":"PSH_ESA","error_description":"Error saving app code"}
PSH_AUN Application unknown {"status":"ko","error_code":"PSH_AUN","error_description":"Application unknown"}
PSH_ESD Error saving device {"status":"ko","error_code":"PSH_ESD","error_description":"Error saving device"}
PSH_ECN Error creating notification {"status":"ko","error_code":"PSH_ECN","error_description":"Error creating notification"}
PSH_IAT Invalid authorization token {"status":"ko","error_code":"PSH_IAT","error_description":"Invalid authorization token"}
Menu module MNU_MNS Menu not specified {"status":"ko","error_code":"MNU_MNS","error_description":"Menu not specified"}
MNU_INF Item not found {"status":"ko","error_code":"MNU_INF","error_description":"Item not found"}
MNU_NIF No items found {"status":"ko","error_code":"MNU_NIF","error_description":"No items found"}
SobiPro module SP_SNI SobiPro not installed {"status":"ko","error_code":"SP_SNI","error_description":"SobiPro not installed"}
SP_SNS Section not specified {"status":"ko","error_code":"SP_SNS","error_description":"Section not specified"}
SP_CNS Category not specified {"status":"ko","error_code":"SP_CNS","error_description":"Category not specified"}
SP_PNS Parent not specified {"status":"ko","error_code":"SP_PNS","error_description":"Parent not specified"}
SP_SGE Section generic error {"status":"ko","error_code":"SP_SGE","error_description":"Section generic error"}
SP_NSF No sections found {"status":"ko","error_code":"SP_NSF","error_description":"No sections found"}
SP_SNF Section not found {"status":"ko","error_code":"SP_SNF","error_description":"Section not found"}
SP_CGE Category generic error {"status":"ko","error_code":"SP_CGE","error_description":"Category generic error"}
SP_NCF No categories found {"status":"ko","error_code":"SP_NCF","error_description":"No categories found"}
SP_CNF Category not found {"status":"ko","error_code":"SP_CNF","error_description":"Category not found"}
SP_EGE Entry generic error {"status":"ko","error_code":"SP_EGE","error_description":"Entry generic error"}
SP_NEF No entries found {"status":"ko","error_code":"SP_NEF","error_description":"No entries found"}
SP_ENF Entry not found {"status":"ko","error_code":"SP_ENF","error_description":"Entry not found"}
ZOO module ZOO_ZNI ZOO not installed {"status":"ko","error_code":"ZOO_ZNI","error_description":"ZOO not installed"}
ZOO_ZNS ZOO app not specified {"status":"ko","error_code":"ZOO_ZNS","error_description":"ZOO app not specified"}
ZOO_INF Item not found {"status":"ko","error_code":"ZOO_INF","error_description":"Item not found"}
ZOO_ANA Access not authorized {"status":"ko","error_code":"ZOO_ANA","error_description":"Access not authorized"}
ZOO_CNS Category not specified {"status":"ko","error_code":"ZOO_CNS","error_description":"Category not specified"}
ZOO_CNF Category not found {"status":"ko","error_code":"ZOO_CNF","error_description":"Category not found"}
ZOO_NCF No categories found {"status":"ko","error_code":"ZOO_NCF","error_description":"No categories found"}
Kunena module KNN_KNI Kunena not installed {"status":"ko","error_code":"KNN_KNI","error_description":"Kunena not installed"}
KNN_NTF No topic found {"status":"ko","error_code":"KNN_NTF","error_description":"No topic found"}
K2 module K2_KNI K2 not installed {"status":"ko","error_code":"K2_KNI","error_description":"K2 not installed"}
K2_NUF No users found {"status":"ko","error_code":"K2_NUF","error_description":"No users found"}
K2_INF Item not found {"status":"ko","error_code":"K2_INF","error_description":"Item not found"}
K2_IGE Item generic error {"status":"ko","error_code":"K2_IGE","error_description":"Item generic error"}
K2_ANA Access not authorized {"status":"ko","error_code":"K2_ANA","error_description":"Access not authorized"}
K2_CNF Category not found {"status":"ko","error_code":"K2_CNF","error_description":"Category not found"}
K2_NCF No categories found {"status":"ko","error_code":"K2_NCF","error_description":"No categories found"}
K2_CGE Category generic error {"status":"ko","error_code":"K2_CGE","error_description":"Category generic error"}
Search module - - -
Community Builder module CB_CNI Community Builder not installed {"status":"ko","error_code":"CB_CNI","error_description":"Community Builder not installed"}
CB_EAD Error accessing database {"status":"ko","error_code":"CB_EAD","error_description":"Error accessing database"}
CB_UNS User not specified {"status":"ko","error_code":"CB_UNS","error_description":"User not specified"}
CB_UNF User not found {"status":"ko","error_code":"CB_UNF","error_description":"User not found"}
CB_MFM Mandatory field missing {"status":"ko","error_code":"CB_MFM","error_description":"Mandatory field missing"}
CB_PUF Profile update failed {"status":"ko","error_code":"CB_PUF","error_description":"Profile update failed"}
Release System module REL_PNS Package not specified {"status":"ko","error_code":"REL_PNS","error_description":"Package not specified"}
REL_ENS Email not specified {"status":"ko","error_code":"REL_ENS","error_description":"Email not specified"}
REL_UNS Username not specified {"status":"ko","error_code":"REL_UNS","error_description":"Username not specified"}
REL_PWD Password not specified {"status":"ko","error_code":"REL_PWD","error_description":"Password not specified"}
REL_KNS Key not specified {"status":"ko","error_code":"CB_MFM","error_description":"Key not specified"}
REL_KNR Key not required {"status":"ko","error_code":"REL_KNR","error_description":"Key not required"}
REL_PNF Package not found {"status":"ko","error_code":"REL_PNF","error_description":"Package not found"}
REL_PNE Package not exists {"status":"ko","error_code":"REL_PNE","error_description":"Package not exists"}
REL_GNS Group not specified {"status":"ko","error_code":"REL_GNS","error_description":"Group not specified"}
REL_GNF Group not found {"status":"ko","error_code":"REL_GNF","error_description":"Group not found"}
REL_UNF User not found {"status":"ko","error_code":"REL_UNF","error_description":"User not found"}
REL_UNA User not authorized {"status":"ko","error_code":"REL_UNA","error_description":"User not authorized"}
REL_INK Invalid key {"status":"ko","error_code":"REL_INK","error_description":"Invalid key"}
REL_ESK Error sending key {"status":"ko","error_code":"REL_ESK","error_description":"Error sending key"}
REL_LIF Login failed {"status":"ko","error_code":"REL_LIF","error_description":"Login failed"}
REL_UNE User not enabled {"status":"ko","error_code":"REL_UNE","error_description":"User not enabled"}
Friday, 18 April 2014 00:00

Usage

Once an end-point is published the web clients can start to make HTTP requests and consume services provided by jBackend API. It is possible to test if all is working as expected using any REST client that allows to build custom HTTP requests (much better if the client supports JSON decode to better show server responses). Some good clients are available as browser plugin for both Firefox and Chrome. We suggest REST Easy for Firefox and Postman - REST Client for Chrome.

jBackend Test End-Point

Let's assume the end-point menu item can be accessed with the following URL:

http://www.mysite.com/index.php/jbackend

Calling just the URL without any parameter we will get the following JSON response:

{
    "status": "ko",
    "error_code": "REQ_MNS",
    "error_description": "Module not specified"
}

Note that the HTTP Response Code is always 200 even in case of errors. The error condition is reported by the "status" value (ok, ko). Additional information about the error can be found in the "error_code" and the "error_description" values.

To check jBackend features it is available a sandbox with the last version of jbackend and all modules installed, and free access type on the end-point. To play with the sandbox a Postman collection is available to download here:

http://www.selfget.com/downloads/file/41-jbackapp-postman-collection.html

It needs only to be imported into Postman and is ready to play.

Push Notifications

jBackend includes a fully featured platform for sending Push Notifications over Google GCM (Android) and Apple APNs (iOS). Moreover, it supports multiple mobile applications, and you can manage them all from a single Joomla installation.

The component interface includes functions to manage Apps, Devices and Notifications, and there's a Push module to interact with jBackend from the outside (e.g. to send registration token from your app or start the push notification sending process).

Friday, 18 April 2014 00:00

Initial configuration

The first thing to do just after installation is to enable jBackend basic plugins. To do this go to menu "Extensions" -> "Plug-in Manager", and filter plugin list for type "jbackend".

jBackend Basic Plugins

Each one of these plugins has some configurable options, so it is enough to click on "Status" buttons to enable the plugins, but it is necessary to edit a plugin to change its settings.

Note that when a plugin is disabled the API functions it provides will NOT be available.

To start using jBackend it is a good practice to publish an "end-point". This is a Joomla menu item which provides a defined URL to access to jBackend APIs (the one associated with the menu link), and can be configured as needed using menu item's options. To create an end-point go to "Menus" -> "Menu Manager", click on the menu that will contain the end-point (or create a new menu, like an hidden menu) and add a new menu item.

jBackend End-Point Menu

Select a menu type "jBackend" -> "Request" and set the "Access type" in the "Options" tab, and other options available for the current endpoint.

jBackend End-Point Options

The following options are available for each endpoint:

Option Description
Access type Specify the kind of access allowed by the endpoint.
Enable trace Enable or disable the logging of each request made at this endpoint.
Enable CORS Add Access-Control-Allow-Origin: * to the response header.
Force SSL Redirect any request on http to the same request on https.
Enabled modules Specify which modules to expose and make accessible on the endpoint (all modules or only selected modules).
Selected modules The list of modules enabled on the endpoint. This option is applied only when "Enabled modules" is "Only selected".

Currently jBackend supports the following access type:

Access type Description
Free End-point can be consumed without any authentication or limitation, just like a guest user can browse the site's pages and with the same restrictions. This means that if an article is restricted to "Register users" only, it will be not accessible for guests even on the end-point, but the client needs to authenticate himself, using the login service. Native ACL are always satisfied with any access type and this should be respected also in case of custom module development.
User End-point usage is restricted to authenticated users only. To consume services the first call must be to login service. If the user can login to the site, then the same credentials are authorized to use the end-point.
API Key End-point needs a valid API Key for each request. The request must include the api_key=<KEY> parameter or it will be rejected. More details on API Key features can be found in the dedicated section.

Note that APIs could be accessed without to publish any end-point, just calling the jBackend component with http://<siteurl>/index.php?option=com_jbackend&<params> (default requests). For this reasons there are global options defined as default and used for such situations. These general options can be accessed by the "Options" button in the jBackend panel. For security reasons the default access is set to "API Key".

jBackend General Options

The following global options are available:

Option Description
Default Access type Specify the kind of access allowed by the default endpoint.
Default Enable trace Enable or disable the logging of each request made on the default endpoint.
Default Force SSL Redirect any request on http to the same request on https on the default endpoint.

REST format

If Joomla SEF is enabled, the endpoint can serve requests with the REST format (e.g. /get/content/articles/<N>).

Joomla SEF Enabled

Friday, 18 April 2014 00:00

Introduction

This documentation is updated to jBackend version 3.6.0.

jBackend is a Joomla extension that introduces a set of APIs for access to all Joomla's content and features, and easily integrate any Joomla site with any external system. It extends the power of Joomla allowing you to use your site as a "backend system" to serve and feed any kind of client (mobile apps, news channels, affiliate sites, and any other external system).

jBackend also provides a full push notifications platform for iOS and Android mobile apps. It is possible to manage multiple apps, to register devices for each app, and to schedule push notifications sending on registered devices, filtered by app and platform type.

jBackend is designed to be "extensible" via plugins. Adding new plugins means to add new APIs to support new Joomla extensions. The basic package already includes three plugins, the User Module (that supports Joomla users and ACL), the Content Module (for the standard Joomla content, categories and articles), and the Push Module (to work with push notifications). New plugins are on the way, to add support for the most used Joomla extensions (e.g. K2, Zoo, VirtueMart, HikaShop, and so on). Additional plugins can be installed separately, so you can install and use only the necessary modules, and keep your CMS lightweight and efficient.

jBackend access is possible through an "end-point", that can be published like a menu item. It is possible to publish several end-points and configure access rules separately for each one. The access can be free, or restricted with a standard user login or through the use of an API Key. API Keys can be generated and configured (e.g. in terms of limitations like expiration or daily access) in jBackend panel. This allows full control on API access provided to clients.

It is possible to enable requests tracking for each endpoint separately. In this way all requests received from the endpoint are stored in the database and can be used for security audit or for statistical analysis.

It is also possible to enable specific modules for each endpoint separately. This increase the control level on the pool of functions or services to expose for each endpoint.

End-point channels can be accessed through HTTP, requests can be compliant to RESTful pattern, and responses are JSON encoded. In the future is expected to support the ability to provide XML responses.

Friday, 18 April 2014 00:00

Installation procedure

jBackend basic extension has just one package to download and install. The package includes the component and three plugins (User Module, Content Module, and Push Module), and support the installation with "upgrade" mode, so there’s no need to uninstall any previous installed version.

To install jBackend, login to Joomla backend as administrator, and go to menu "Extension Manager". Click the browse button, select the package file (jBackendX.X_J3.zip) and click the installation button.

jBackend Installation

The package will be uploaded on the server and then installed. After installation finished a message will report a successful message.

jbackend installation done

That’s all. Now we are ready to start using jBackend.

Upgrade procedure

When upgrading from a previous version of jBackend, there is no need to first uninstall the old package. As mentioned earlier, jBackend supports the "upgrade" mode for the installation, so is enough to just install the new package over the old one. The component and the three plugins included in the basic package will be upgraded.

Note that during the upgrade also the database tables are upgraded when needed, but without to delete or loose any table data. It is in charge of the installation process to upgrade tables structure if needed. All the data (e.g. API Keys) will be preserved.

Page 3 of 4