Creating Hybrid Apps with Liferay DXP Headless API and Ionic Framework

Step by step guide

If you are thinking of creating a hybrid mobile application for Android and iOS devices, surely you could have heard of the Ionic Framework.
Personally, I think it is among one of the most complete and simple to use open source solution and today I would like to explain how to use Liferay DXP API to create a simple app that can show the blog posts of a site within our Liferay instance.

1. Find the API
First of all we need to identify which is the most correct API to use to get blog posts. Liferay provides the list of APIs available on SwaggerHub, accessible at: https://app.swaggerhub.com/organizations/liferayinc
The list of APIs related to blog posts is available in the headless-delivery section: https://app.swaggerhub.com/apis/liferayinc/headless-delivery/v1.0

The API used is GET /v1.0/sites/{siteId}/blog-postings and the complete address relating to a Liferay DXP instance in a local default environment is:
http://localhost:8080/o/headless-delivery/v1.0/sites/{siteId}/blog-postings

2. Find the Site Id
It is possible to identify the Site Id by going to Configuration -> Settings in the "Site Administration Menu" of Liferay DXP.

3. Create Ionic App
Install Node.Js and NPM on your computer and then install the Ionic CLI, then create a new project and start the local development server for our app:

npm install -g @ionic/cli
ionic start myApp sidemenu
cd myApp
ionic serve


4. Create Rest Service 
In order to call the Liferay DXP APIs from our Ionic app, create a simple Provider to have a single point of access within our App to manage the types of REST calls.

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { map } from 'rxjs/operators';

let apiBaseUrl = 'http://localhost:8080/o/headless-delivery/v1.0/sites/';
let siteId = "xxx";
let apiUrl = apiBaseUrl + siteId + "/blog-postings?sort=dateCreated%3Adesc";
let username = 'test';
let password = 'test';
let token = btoa(username + ":" + password);

@Injectable()
export class RestService {

  constructor(
    public http: HttpClient) {
  }

  getData(type){

    return new Promise((resolve, reject) =>{
      let headers = new HttpHeaders({
        'Content-Type':  'application/json',
        'Authorization': 'Basic ' + token + ''
      });

      this.http.get(apiUrl + type, {headers}).
      subscribe(res =>{
        resolve(res);
      }, (err) =>{
        reject(err);
      });
    });
  }
}

By default, for calling the APIs, authentication is required and Liferay DXP offers 3 modes:

  • Basic Authentication
  • OAuth 2.0
  • Cookie / Session Authentication

For this example, I used Basic Authentication mode and to use it, just add the string with Base64-encoded username and password in the HTTP Call Header:

"Authorization: Basic dGVzdEBleGFtcGxlLmNvbTpMaWZlcmF5Cg=="

Full documentation: https://help.liferay.com/hc/en-us/articles/360039026192-Making-Authenticated-Requests

5. Showing the Blog Post
Let's put together what has been done so far and create what is necessary to show blog posts within our App.
Create a new page within the App using the command:

ionic g page "Blog Post"

Open the generated file "blog-post.page.ts", import our "RestService" and add the call to the Liferay DXP API in the "ngOnInit ()" method to get the blog posts.

import { Component, OnInit } from '@angular/core';
import { RestService } from "../providers/rest-service";

@Component({
  selector: 'app-blog-post',
  templateUrl: './blog-post.page.html',
  styleUrls: ['./blog-post.page.scss'],
})
export class BlogPostPage implements OnInit {
  public blogPost: any;
  constructor(
    public restService: RestService
  ) { }

  ngOnInit() {
    this.restService.getData("/blog-postings?sort=dateCreated%3Adesc").then((result) => {
      this.blogPost = result.items;
    }, (err) => {
      //Connection failed message
      console.log("Fail!");
    });
  }
}

At the end, let's modify the generated file "blog-post.page.html" to show the posts obtained by the API:

<ion-card *ngFor="let item of blogPost">
    <img src="http://localhost:8080/{{item.image.contentUrl}}" />
    <ion-card-header>
      <ion-card-subtitle>{{item.creator.name}}</ion-card-subtitle>
      <ion-card-title>{{item.headline}}</ion-card-title>
    </ion-card-header>
    <ion-card-content>
      {{item.alternativeHeadline}}
    </ion-card-content>
  </ion-card>

Result

Full code repository: https://github.com/lorenzo-carbone/ionic-dxp

Thanks!