April 21, 2017
Install Apigility
I find the easiest way to accomplish this on the IBM i is to use php itself on command line:
$ php -r "readfile('https://apigility.org/install');" | php
After this is ran, Apigility will try to serve itself up. While it is successful in doing so, I have not been able to visit Apigility without errors when it is running this way on the IBM i. Therefore, I set it up normally through apache:
<VirtualHost *:80>
ServerName api.ibmiserver.com
DocumentRoot /path/to/apigility/public
<Directory "/path/to/apigility/public">
Options FollowSymLinks
order allow,deny
allow from all
AllowOverride all
</Directory>
AllowEncodedSlashes On
</VirtualHost>
That should do it! Apigility should be running fine at the address provided as ServerName.
Create a DB2 database adapter
Click on Database
in the upper navigation, then click New DB Adapter
in the content area.
Fill out the necessary fields and click Save
.
The adapter options can be added and edited through the interface as well:
If left with no options set, then we are limited to using the dot
syntax, (library.file
) only. All column names
will be uppercase as well. Some helpful options to set in local.php
:
<?php
// config/autoload/local.php
return [
'db' => [
'adapters' => [
'ibmdb' => [
'database' => 'SXXXXXXX',
'driver' => 'IbmDb2',
'username' => 'user',
'password' => 'password',
'driver_options' => [
'i5_naming' => 1, // This allows us to write with slashes as well. LIBRARY/FILE
'db2_attr_case' => 1, // This forces all returned column names to lowercase. Personal preference.
// Other helpful options can be found at: http://php.net/manual/en/function.db2-connect.php
],
]
],
],
];
Create an API and a Service
This part is fairly straightforward. Either follow the official documentation for creating rest services, or create a simple REST service for test purposes, which is what I’m going to do here.
I created an API called Test with a REST service called Test. All the Test service does is return all PTFs with updates available when a GET request is sent for a collection.
So if we call http://api.ibmiserver.com/test
through a service like Postman, we should get something like:
{
"_links": {
"self": {
"href": "http://test.api.t-r.com/test"
}
},
"_embedded": {
"test": [
{
"ptf_group_currency": "PSP INFORMATION NOT AVAILABLE",
"ptf_group_id": "SF99145",
"ptf_group_title": "PERFORMANCE TOOLS",
"ptf_group_level_installed": 9,
"ptf_group_level_available": null,
"ptf_group_last_updated_by_ibm": null,
"ptf_group_release": "V7R1M0",
"ptf_group_status_on_system": "INSTALLED"
},
{
"ptf_group_currency": "PSP INFORMATION NOT AVAILABLE",
"ptf_group_id": "SF99362",
"ptf_group_title": "BACKUP RECOVERY SOLUTIONS",
"ptf_group_level_installed": 54,
"ptf_group_level_available": null,
"ptf_group_last_updated_by_ibm": null,
"ptf_group_release": "V7R1M0",
"ptf_group_status_on_system": "INSTALLED"
}
]
},
"total_items": 2
}
Poor Man’s REST
Instead of relying Entity and Collection definitions, which would be the proper way, I have used a barebones approach to creating RESTful services when on the IBM i. This is largely due to the data I deal with daily, which is non-normalized and has column names that sometimes use special characters. Let’s take a look at the Resource and ResourceFactory for this service in case others need to take this same approach.
<?php
// module/Test/src/V1/Rest/Test/TestResourceFactory.php
namespace Test\V1\Rest\Test;
class TestResourceFactory
{
/**
* This is so PHPStorm knows what type of Object $services is.
* @param \Zend\ServiceManager\ServiceManager $services
* @return TestResource
*/
public function __invoke($services)
{
// Grab the ibmdb service we created earlier to define our database
$db = $services->get('ibmdb');
// Inject that database into TestResource for use in the Test REST service.
return new TestResource($db);
}
}
<?php
// module/Test/src/V1/Rest/Test/TestResource.php
namespace Test\V1\Rest\Test;
use ZF\ApiProblem\ApiProblem;
use ZF\Rest\AbstractResourceListener;
class TestResource extends AbstractResourceListener
{
/**
* Define $db variable
* @var \Zend\Db\Adapter\Adapter $db
*/
private $db;
public function __construct($db) {
// Initiate $db variable with what is injected from the factory
$this->db = $db;
}
/**
* Fetch all or a subset of resources
*
* @param array $params
* @return ApiProblem|mixed
*/
public function fetchAll($params = [])
{
$sql = <<<SQL
SELECT * FROM SYSTOOLS.GROUP_PTF_CURRENCY
ORDER BY PTF_GROUP_LEVEL_AVAILABLE - PTF_GROUP_LEVEL_INSTALLED DESC
SQL;
$resultSet = $this->db->query($sql, []);
return $resultSet->toArray();
}
}
While it isn’t ideal to be running raw sql in the Resource, sometimes we don’t have much choice, and I wanted to demonstrate a simple way to get started on the IBM i. That’s it for now. Stay tuned for Apigility + OAuth2 on the IBM i and how to digest these services with Angular2.