Developing JSON API with Joomla Framework

Written by | 01 September 2014 | Published in 2014 September
At the end of 2013 I was asked to develop a web app for creating interactive calculators called Calculoid. It was as exciting for me as for a kid at candy store, first because I was the one who could choose technologies for this project, and second because it was the same week the shiny new Joomla Framework was released. I decided to develop the app as a Single Page Application (SPA) with AngularJS at the client side and at the server side I decided to use, as you can probably guess, the Joomla Framework.
Calculoid App source Calculoid App source Jan Linhart

The client side - AngularJS

Single page applications work slightly different than most Joomla users and developers are used to. It does not refresh the page at all. The URL does not change. Well, the part after the hash (#) does. Quick example:

http://some-domain.com/#/the-part-which-can-be-changed-by-JS

The most of business logic happens in the client’s browser. AngularJS makes it very pleasant to work with the after-hash routes as well as template system, custom directives, services, ajax requests and so forth. It uses completely different logic than MooTools or jQuery and when you get used to it, it really makes sense. I advise everyone to try it.

The server side - Joomla Framework

The server provides data to the AngularJS app whenever it asks. Server does not return the whole HTML document, but only data in JSON format which has changed at the page. I’ll describe the client - server communication in more detail below. Apart from serving data, server takes care about user permissions.

The JSON REST API

The client and the server communicates via asynchronous HTTP requests. Because of the two way binding feature and advanced templating system of AngularJS, it is very easy to generate HTML inside of the client’s browser. Therefore the JSON format is used for communication between client and server. JSON is simple to work with for both PHP and JS. Requests are then much lighter without additional HTML tags and the parts of the page which were not changed.

Think about it. For example: footer, menu, logo. It is very often the same at every single page of most websites, but it is generated and sent via each HTTP request. With a SPA, it is loaded once and modified if needed. A lot of bandwidth, energy and time is saved.

If you are thinking about creating some web app with JSON REST API, give apiary.io a try. It’s tool for API designing and testing.

Joomla Framework (JF) experience

Finally, when we know for what purpose the JF was used, let’s talk about experience I gained during development of the JSON REST API server.

Getting started

It wasn’t as easy to get started with JF as I expected. I pulled JF from GitHub and then I was lost. New library is great, but how to start? Fortunately, I’ve found sample JF app from David Hurley at GitHub which saved me. I could see how the structure of the app should look like and how to connect pieces together. Now, the link to David’s app is at front page of JF website, so you shouldn’t miss it.

Let’s take a look at few features of JF and David’s sample app which were completely new for me.

Router

I really enjoyed how David used the router at his sample app. It is not how JF force you to implement it, it is just one way how to do it. I was often confused on how does Joomla CMS router work. It is so complicated that it caused me bad dreams few times. Anyway, take a look at David’s router:

https://github.com/dbhurley/framework-app/blob/master/App/Config/routes.json

Simple json file where you define all types of URI you need and which controller should handle the request. It is simple but not stupid. Look closely to:

"news/:task/:id": "\\Controller\\NewsController"

:task and :id are variables which are part of HTTP request variables when you need them. These URI are equivalent:

/news/save/33 /news?task=save&id=33

Namespaces

JF is cutting edge PHP framework and it uses Composer’s autoloading which is very cool. I didn't have to include or require any PHP file at all. Well, it is necessary to include the autoloader to index.php, but David did that for me with his sample app which I used as a base for my app.

Joomla CMS solved the class name problem with the J prefix. So instead of Date class, Joomla CMS has JDate class. Namespaces allowed JF to have normal class names without worrying about collisions with other class called also Date.

If you are not familiar with namespaces, take a look at first few lines of one of this model to see live example:

https://github.com/dbhurley/framework-app/blob/master/App/Model/NewsModel.php

A class is assigned to a namespace like this:

namespace App\Model;

class NewsModel { … } 

It means that the NewsModel  class can be accessed at the App\Model namespace. The main reason for namespaces is that there can exist the same NewsModel classat App2\Model namespace. You can decide which one you want to use specifying what namespaces should be loaded to a file (for example to a view) like this:

use App\Model\NewsModel; 

It is very good idea to use namespaces when you load other libraries together with JF. And you will, because it is so damn easy with Composer. The probability that there will be two PHP classes with the same name is quite high then.

Usage of namespaces is charming. If you specify a namespace like above example, you can use only NewsModel from the App\Model namespace (folder). If you specify it more vaguely:

use App\Model;

Then you can use all models from App/Model namespace. When I’m writing “use a model”, I mean to create new instance like this:

$newsModel = new NewsModel;

It is also possible to use NewsModel without specifying it at the top of the class file, but then you have to create the new object with full namespace path:

$newsModel = new \App\Model\NewsModel;

Which is not that clean in my opinion, so I would suggest to define all used namespaces before the class.

It is also possible to use 2 classes with the same name in one file without getting an error when you use aliases like this: 

use Joomla\Date as JDate;

use App\Date;

One more thing I should mention to save you some debugging time. PHP generic classes will not work as you are used to. For example:

$emptyObject = new stdClass; // fires an error

Because you did not specify the namespace. This is correct way to do it:

$emptyObject = new \stdClass; // everything is cool like that 

Dependency Injection (DI)

As a Joomla extension developer, I was very used to use static methods like JFactory::something() which I could call from any file I wanted. It is very easy to use, but from the software architecture point of view, it is not a good design. Mainly because the code with static classes/methods is hard to test. It’s also not considered as good OOP practice.

Even though I don’t think I got it completely ‘by the book’ at my app, I’ll try to explain it so you will. Let’s take our NewsModel as an example. News has an author. How do we load current author / user while saving the news when there is no JFactory::getUser()? Few options come to my mind.

A) Create a new User instance wherever I need it.

namespace App\Models

use App\Helpers\User

class NewsModel

{

   public function save()

   }

       $user = new User();

       $user->loadCurrentUser();

       // ...

   }

}

That may not be optimal way how to do it, because it can load current user many times from different locations and each instance of the User class can be in different state at one time which can become a little confusing.

B) Create the new User inside the constructor.

namespace App\Models

use App\Helpers\User

class NewsModel

{

   protected $user;

   public function __construct()

   {

       $this->user = new User();

   } 

   public function save()

   }

       $this->user->loadCurrentUser();

       // ...

   }

}

This is better, because the NewsModel has only one instance of the User class for all it’s methods. I presume that loadCurrentUser is smart method which does not load user form database as many times as it is called, but only once and then remembers it. But wait, I may need to use the User at other classes as well. So I’m back where I was before.

C) Create a new User globally for the whole app and inject it to objects which depends on it. Hey, that sounds like Dependency Injection.

namespace App\Models

use App\Helpers\User 

class NewsModel

{

   protected $user;

   public function __construct(User $user)

   {

       $this->user = $user;

   }

   public function save()

   }

       $this->user->loadCurrentUser();

       // ...

   }

}

That’s it! DI isn’t that difficult after all. Note that I have specified the constructor’s parameter is type of User. Guess what happens if someone will create new NewsModel with parameter of different type like this:

$newsModel = new NewsModel(‘John Doe’);

Yes, you guessed it:

“Catchable fatal error: Argument 1 passed to NewsModel::__construct() must be an instance of User, string given, called in … and defined in ...”

That’s the best described error I’ve ever seen in PHP. Isn’t it beauty?

D) DI Container

You can go one step further and use DI Container which is a package of JF. That’s basically one class where you inject the most used objects (Database object, Config object, User object...) and then you inject this DI Container as dependency of the NewsModel. I would say that DI Container is analogy of JFactory class.

Documentation

Documentation is weak part of every (new) project. Who wants to spent time on documentation when new feature can be developed instead. But developers of JF have done a great job. Let me tell you an example from my experience when I had problem with missing documentation.

I wanted to let users of my app to authenticate with their Google account.

1. option - Google 

Search for “joomla framework google oauth 2”. Even now, just 6 month after the JF release, you can find answered questions about how to use Google oauth 2 with JF. That’s amazing for such a new project. At time I needed it, there was nothing.

I saw at Joomla Day Prague that a lot of attendees were confused about the name. “Hm, Joomla Framework. Wasn’t it the name of predecessor of Joomla Platform?” Well, not only people are confused, but Google as well. So you’ll get a lot of irrelevant search results when you search for Joomla Framework.

2. option - GitHub Readme

I’ve discovered that each package has it’s own documentation right below the code at GitHub. Take a look at JF’s Google API package:

https://github.com/joomla-framework/google-api

As you can see, it is well described with examples. Sadly, in time of writing this article, there was missing how to use Google Oauth2 which is part of this package.

3. option - Tests

If you didn’t find an example how to use the code you need, go to Tests folder and find it. JF has great test coverage. Test = example of usage. See for yourself:

https://github.com/joomla-framework/google-api/blob/master/Tests/JGoogleAuthOauth2Test.php#L59

4. option - Composer

If you really do not get a part of JF working for you, then use any other library you are comfortable with. That’s the most awesome part of JF, that you don’t have to use it for everything. It even encourages you to do so. That’s why is JF divided into small independent packages. You can pick each package from different library. That I call freedom.

To finish with the Google oauth 2 example, I used well described library directly from Google (https://developers.google.com/api-client-library/php).

Conclusion

Do you want to use latest technologies today? Do you want to learn how to write better OOP code? Do you want freedom at what you can use for each part of your app? If your answers to those questions are “hell, yeah”, then what are you waiting for? Joomla Framework is exactly what you need!

Tagged under Developers, English
Jan Linhart

Jan Linhart

Jan is one of the few lucky people who loves his job. Each day he solves world problems with opensource software. Jan is proud member of EasyJoomla and Webspark team. Apart from developing several Joomla extensions he is also author of constimator.com and calculoid.com.