drew.d.lenhart

programming, software, technology, anything on my mind...

Getting Started with a JSON API using Slim Part 2

2016/01/31

In the last article, I showed how to get started with a Slim JSON API. I had so much fun with it that I thought I would build on the API and correct a couple wrongs.

To recap, I came up with the scenario that we wanted to collect CPU / MEMORY / C: Drive utilization from a computer. I'm not showing how to do this portion. If you wanted you could create a Python or Powershell script to gather this information. But lets assume that in whatever gathering script is used to get the utilization we didn't want to connect directly to the database. There could me numerous reasons for wanting to insert data via an API. For this we need a post route that can be used to INSERT data.

This is a demonstration, don't use this code on your production system unless there is some form of authentication!

Composer

Lets update the composer.json file to include our database.class.php file. This allows us to not include in the index.php.

If you followed the last article, and have composer set up correctly, edit composer.json to:

{
{
    "require": {
        "slim/slim": "~2.6"
    },
        "autoload": {
        "files": [
            "includes/database.class.php"   
        ]
    }
}

Run the Composer update command (I'm on OSX):

php composer.phar update

Database

Add an insert helper and close connection method to database.class.php:


    //insert data
    function insertData($query, $data){
        $queryEx = $this->pdo->prepare($query);
        return $queryEx->execute($data);
    }

    //close connection
    function closeConn(){
        $this->pdo = null;      
    }
    

Slim

Assuming you set up the database correctly from the first article, we can create the post route.

http://localhost/api/insertUtil *The desired endpoint.

Because we set the ID in the table to Auto Increment and Date to TIMESTAMP, we don't need to insert this data.


$app->post('/api/insertUtil', function() use($app) {
    $posts = $app->request->post();
    $cpu = $posts['cpu'];
    $mem = $posts['mem'];
    $disk = $posts['disk'];

    $db = database::getInstance();

    try 
    {
         $data = array(
            ':cpu' => $cpu,
            ':mem' => $mem,
            ':cdrive' => $disk);

        $sql= 'INSERT INTO c_utilization (c_cpu, c_mem, c_cdrive) VALUES (:cpu,:mem,:cdrive)';

        //use helper methods in includes/database.class.php
        $db->insertData($sql, $data);

        $app->response->setStatus(200);
        $app->response()->headers->set('Content-Type', 'application/json');
        $app->response()->headers->set('Access-Control-Allow-Origin', '*');
        echo json_encode(array("status" => "success", "code" => 1));
        //close connection
        $db->closeConn();

    } catch(PDOException $e) {
        $app->response()->setStatus(404);
        $app->response()->headers->set('Access-Control-Allow-Origin', '*');
        echo '{"error":{"text":'. $e->getMessage() .'}}';
    }

});

Heres the full index.php app. Notice how I re-named the get routes. Since in the first article I used /api/:type, it created some restrictions, I renamed the get routes to:

http://localhost/api/get/utilization <- Get all entries ordered by date http://localhost/api/get/currentUtil <- Get latest entry

<?php
//Title:              stJSONAPI - Tutorial Code
//DESC:               Json api example
//Auth:               Drew Lenhart - www.drewlenhart.com
//Last Update:        02/08/15

//Database info:
//c_id = ID; c_cpu = CPU; c_mem = MEMORY; c_cdrive = c:\ DRIVE; c_date = TIMESTAMP

require 'vendor/autoload.php';

$app = new \Slim\Slim();

/*#### - MAIN - ####*/
$app->get('/', function() use($app) {
    $app->response->setStatus(200);
    echo "Welcome to my JSON API!";
}); 

/*
#### - GET CURRENT UTILIZATION/ALL NUMBERS - ####
e.g.
http://localhost/api/get/utilization = get all entries.
http://localhost/api/get/currentUtil = get current entry.
*/
$app->get('/api/get/:type', function($type) use($app) {

    $db = database::getInstance();

    try 
    {
        //use get $type from URL and use helper methods in database.class.php
        If ($type == 'utilization'){
            $sql = "SELECT * FROM c_utilization ORDER BY c_date ASC";
            $stmt = $db->getData($sql);

        }else if ($type == 'currentUtil'){
            $sql = "SELECT * FROM c_utilization ORDER BY c_date DESC";
            $stmt = $db->getDataSingle($sql);

        }else{
            echo "Incorrect parameter!  Please check url.";
            break;
        }

        if($stmt) {
            $app->response->setStatus(200);
            $app->response()->headers->set('Content-Type', 'application/json');
            $app->response()->headers->set('Access-Control-Allow-Origin', '*');
            echo json_encode($stmt);
            $db = null;
        } else {
            throw new PDOException('No records found.');
        }

    } catch(PDOException $e) {
        $app->response()->setStatus(404);
        $app->response()->headers->set('Access-Control-Allow-Origin', '*');
        echo '{"error":{"text":'. $e->getMessage() .'}}';
    }

});

/*
#### - INSERT CURRENT UTILIZATION NUMBERS - ####
e.g.
http://localhost/api/insertUtil = insert entry.
*/

$app->post('/api/insertUtil', function() use($app) {
    $posts = $app->request->post();
    $cpu = $posts['cpu'];
    $mem = $posts['mem'];
    $disk = $posts['disk'];

    $db = database::getInstance();

    try 
    {
         $data = array(
            ':cpu' => $cpu,
            ':mem' => $mem,
            ':cdrive' => $disk);

        $sql= 'INSERT INTO c_utilization (c_cpu, c_mem, c_cdrive) VALUES (:cpu,:mem,:cdrive)';

        //use helper methods in includes/database.class.php
        $db->insertData($sql, $data);

        $app->response->setStatus(200);
        $app->response()->headers->set('Content-Type', 'application/json');
        $app->response()->headers->set('Access-Control-Allow-Origin', '*');
        echo json_encode(array("status" => "success", "code" => 1));
        //close connection
        $db->closeConn();

    } catch(PDOException $e) {
        $app->response()->setStatus(404);
        $app->response()->headers->set('Access-Control-Allow-Origin', '*');
        echo '{"error":{"text":'. $e->getMessage() .'}}';
    }

});

//RUN!!
$app->run();

?>

Testing

Fire up the terminal and insert this command, or however you have your development environment set up:

curl -i --data "cpu=74&mem=62.3&disk=18.4" http://localhost/api/insertUtil

You should see something like the following:

Screen Shot 2016-02-10 at 7.32.33 AM

Check the /api/get/currentUtil route and see your entry!

Screen Shot 2016-02-14 at 7.02.18 PM

Final

What we did was create three endpoints. One for grabbing ALL entries, current entry, and inserting an entry! Now that we have everything we need, in the next article I'll show how to use this data in AMCharts!

--Drew