Tutorial Phalcon 3 : Membuat RESTful API Sederhana

Dalam tutorial Phalcon ini, kami akan menjelaskan cara membuat aplikasi sederhana yang menyediakan RESTful API menggunakan metode HTTP yang berbeda:

  • GET untuk mengambil dan mencari data
  • POST untuk menambahkan data
  • PUT untuk memperbarui data
  • DELETE untuk menghapus data

Mendefinisikan API 

API terdiri dari metode berikut ini:

Metode URL Tindakan
GET /Api/robot Mengambil semua data dari tabel robot
GET /Api/robot/search/Astro Pencarian untuk robot dengan nama ‘Astro’
GET /Api/robots/2 Mengambil robot berdasarkan primary key
POST /Api/robot Menambahkan sebuah robot baru
PUT /Api/robots/2 Update robot berdasarkan primary key
DELETE /Api/robots/2 Menghapus robot berdasarkan primary key

Membuat Aplikasi 

Karena aplikasi ini begitu sederhana, kita tidak perlu mengimplementasikan MVC sepenuhnya dalam pengembangan. Dalam hal ini, kita akan menggunakan aplikasi mikro untuk mencapai tujuan kita.

Struktur Berkas berikut ini lebih dari cukup:

my-rest-api/
    models/
        Robots.php
    index.php
    .htaccess

Pertama, kita perlu file .htaccess yang berisi semua aturan untuk rewrite URI ke file index.php, yaitu aplikasi kita:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ index.php?_url=/$1 [QSA,L]
</IfModule>

Kemudian, dalam file index.php kita membuat hal-hal berikut:

<?php

$app = new \Phalcon\Mvc\Micro();

//define the routes here

$app->handle();

Sekarang kita akan membuat rute seperti yang telah didefinisikan di atas:

<?php

$app = new Phalcon\Mvc\Micro();

//Retrieves all robots
$app->get('/api/robots', function() {

});

//Searches for robots with $name in their name
$app->get('/api/robots/search/{name}', function($name) {

});

//Retrieves robots based on primary key
$app->get('/api/robots/{id:[0-9]+}', function($id) {

});

//Adds a new robot
$app->post('/api/robots', function() {

});

//Updates robots based on primary key
$app->put('/api/robots/{id:[0-9]+}', function() {

});

//Deletes robots based on primary key
$app->delete('/api/robots/{id:[0-9]+}', function() {

});

$app->handle();

Setiap route didefinisikan dengan metode bernama yang sama dgn metode HTTP, parameter pertama kita isikan pola route, diikuti oleh handler. Dalam kasus ini, handler adalah fungsi anonim. Route sebagai berikut: ‘/api/robot/{id:[0-9]+}’, sebagai contoh, secara eksplisit menetapkan bahwa format parameter “id”  harus numerik.

Ketika route yang ditetapkan sesuai dengan URI yang diminta maka aplikasi mengeksekusi handler yang sesuai.

Membuat Model 

API menyediakan informasi tentang ‘robot’, data ini disimpan dalam database. Model berikut ini memungkinkan kita untuk mengakses tabel yang dalam cara berorientasi objek. Kita telah menerapkan beberapa bussiness rule dengan menggunakan built-in validator dan aturan validasi sederhana. Melakukan hal ini akan memberi kita ketenangan pikiran dimana data yg disimpan telah memenuhi persyaratan aplikasi kita:

<?php

use Phalcon\Mvc\Model,
    Phalcon\Mvc\Model\Message,
    Phalcon\Mvc\Model\Validator\InclusionIn,
    Phalcon\Mvc\Model\Validator\Uniqueness;

class Robots extends Model
{

    public function validation()
    {
        //Type must be: droid, mechanical or virtual
        $this->validate(new InclusionIn(
            array(
                "field"  => "type",
                "domain" => array("droid", "mechanical", "virtual")
            )
        ));

        //Robot name must be unique
        $this->validate(new Uniqueness(
            array(
                "field"   => "name",
                "message" => "The robot name must be unique"
            )
        ));

        //Year cannot be less than zero
        if ($this->year < 0) {
            $this->appendMessage(new Message("The year cannot be less than zero"));
        }

        //Check if any messages have been produced
        if ($this->validationHasFailed() == true) {
            return false;
        }
    }

}

Sekarang, kita harus mengatur koneksi yang akan digunakan oleh model ini dan memuatnya dalam aplikasi kami:

<?php

// Use Loader() to autoload our model
$loader = new \Phalcon\Loader();

$loader->registerDirs(array(
    __DIR__ . '/models/'
))->register();

$di = new \Phalcon\DI\FactoryDefault();

//Set up the database service
$di->set('db', function(){
    return new \Phalcon\Db\Adapter\Pdo\Mysql(array(
        "host" => "localhost",
        "username" => "asimov",
        "password" => "zeroth",
        "dbname" => "robotics"
    ));
});

//Create and bind the DI to the application
$app = new \Phalcon\Mvc\Micro($di);

Mengambil data 

Yang pertama “handler” yang kita akan terapkan yaitu metode GET untuk memberikan semua data robot yang tersedia. Mari kita gunakan PHQL untuk melakukan query sederhana ini mengembalikan hasil sebagai JSON:

<?php

//Retrieves all robots
$app->get('/api/robots', function() use ($app) {

    $phql = "SELECT * FROM Robots ORDER BY name";
    $robots = $app->modelsManager->executeQuery($phql);

    $data = array();
    foreach ($robots as $robot) {
        $data[] = array(
            'id' => $robot->id,
            'name' => $robot->name,
        );
    }

    echo json_encode($data);
});

PHQL , memungkinkan kita untuk menulis query menggunakan tingkat-tinggi, dialek SQL object-oriented yang diterjemahkan secara internal ke pernyataan SQL yang tepat tergantung pada sistem database yang digunakan. Klausul “use” dalam fungsi anonim akan memberikan akses variabel globel selayaknya variabel local.

Handler pencarian berdasarkan nama akan terlihat seperti berikut:

<?php

//Searches for robots with $name in their name
$app->get('/api/robots/search/{name}', function($name) use ($app) {

    $phql = "SELECT * FROM Robots WHERE name LIKE :name: ORDER BY name";
    $robots = $app->modelsManager->executeQuery($phql, array(
        'name' => '%' . $name . '%'
    ));

    $data = array();
    foreach ($robots as $robot) {
        $data[] = array(
            'id' => $robot->id,
            'name' => $robot->name,
        );
    }

    echo json_encode($data);

});

Mencari berdasarkan kolom “id” caranya mirip, dalam hal ini, kita juga memberitahukan jika robot itu ditemukan atau tidak:

<?php

//Retrieves robots based on primary key
$app->get('/api/robots/{id:[0-9]+}', function($id) use ($app) {

    $phql = "SELECT * FROM Robots WHERE id = :id:";
    $robot = $app->modelsManager->executeQuery($phql, array(
        'id' => $id
    ))->getFirst();

    //Create a response
    $response = new Phalcon\Http\Response();

    if ($robot == false) {
        $response->setJsonContent(array('status' => 'NOT-FOUND'));
    } else {
        $response->setJsonContent(array(
            'status' => 'FOUND',
            'data' => array(
                'id' => $robot->id,
                'name' => $robot->name
            )
        ));
    }

    return $response;
});

Menambah Data 

Mengambil data sebagai string JSON yg disertakan pada request, kita juga menggunakan PHQL untuk insert data:

<?php

//Adds a new robot
$app->post('/api/robots', function() use ($app) {

    $robot = $app->request->getJsonRawBody();

    $phql = "INSERT INTO Robots (name, type, year) VALUES (:name:, :type:, :year:)";

    $status = $app->modelsManager->executeQuery($phql, array(
        'name' => $robot->name,
        'type' => $robot->type,
        'year' => $robot->year
    ));

    //Create a response
    $response = new Phalcon\Http\Response();

    //Check if the insertion was successful
    if ($status->success() == true) {

        //Change the HTTP status
        $response->setStatusCode(201, "Created");

        $robot->id = $status->getModel()->id;

        $response->setJsonContent(array('status' => 'OK', 'data' => $robot));

    } else {

        //Change the HTTP status
        $response->setStatusCode(409, "Conflict");

        //Send errors to the client
        $errors = array();
        foreach ($status->getMessages() as $message) {
            $errors[] = $message->getMessage();
        }

        $response->setJsonContent(array('status' => 'ERROR', 'messages' => $errors));
    }

    return $response;
});

Memperbarui Data 

Update data mirip dengan penyisipan.“id” dikirimkan sebagai parameter yg menunjukan data robot mana yg diperbaharui:

<?php

//Updates robots based on primary key
$app->put('/api/robots/{id:[0-9]+}', function($id) use($app) {

    $robot = $app->request->getJsonRawBody();

    $phql = "UPDATE Robots SET name = :name:, type = :type:, year = :year: WHERE id = :id:";
    $status = $app->modelsManager->executeQuery($phql, array(
        'id' => $id,
        'name' => $robot->name,
        'type' => $robot->type,
        'year' => $robot->year
    ));

    //Create a response
    $response = new Phalcon\Http\Response();

    //Check if the insertion was successful
    if ($status->success() == true) {
        $response->setJsonContent(array('status' => 'OK'));
    } else {

        //Change the HTTP status
        $response->setStatusCode(409, "Conflict");

        $errors = array();
        foreach ($status->getMessages() as $message) {
            $errors[] = $message->getMessage();
        }

        $response->setJsonContent(array('status' => 'ERROR', 'messages' => $errors));
    }

    return $response;
});

Menghapus Data 

Menghapus data caranya jg sama. “id” dikirimkan untuk mengetahui data robot mana yg dihapus:

<?php

//Deletes robots based on primary key
$app->delete('/api/robots/{id:[0-9]+}', function($id) use ($app) {

    $phql = "DELETE FROM Robots WHERE id = :id:";
    $status = $app->modelsManager->executeQuery($phql, array(
        'id' => $id
    ));

    //Create a response
    $response = new Phalcon\Http\Response();

    if ($status->success() == true) {
        $response->setJsonContent(array('status' => 'OK'));
    } else {

        //Change the HTTP status
        $response->setStatusCode(409, "Conflict");

        $errors = array();
        foreach ($status->getMessages() as $message) {
            $errors[] = $message->getMessage();
        }

        $response->setJsonContent(array('status' => 'ERROR', 'messages' => $errors));

    }

    return $response;
});

Menguji Aplikasi 

Menggunakan curl, kita akan menguji setiap route dalam aplikasi kita, memverifikasi apakah operasi sudah tepat:

Mendapatkan semua robot:

curl -i -X GET http://localhost/my-rest-api/api/robots

HTTP/1.1 200 OK
Date: Wed, 12 Sep 2012 07:05:13 GMT
Server: Apache/2.2.22 (Unix) DAV/2
Content-Length: 117
Content-Type: text/html; charset=UTF-8

[{"id":"1","name":"Robotina"},{"id":"2","name":"Astro Boy"},{"id":"3","name":"Terminator"}]

Cari robot berdasarkan nama:

curl -i -X GET http://localhost/my-rest-api/api/robots/search/Astro

HTTP/1.1 200 OK
Date: Wed, 12 Sep 2012 07:09:23 GMT
Server: Apache/2.2.22 (Unix) DAV/2
Content-Length: 31
Content-Type: text/html; charset=UTF-8

[{"id":"2","name":"Astro Boy"}]

Mendapatkan robot berdasarkan ID-nya:

curl -i -X GET http://localhost/my-rest-api/api/robots/3

HTTP/1.1 200 OK
Date: Wed, 12 Sep 2012 07:12:18 GMT
Server: Apache/2.2.22 (Unix) DAV/2
Content-Length: 56
Content-Type: text/html; charset=UTF-8

{"status":"FOUND","data":{"id":"3","name":"Terminator"}}

Masukkan robot baru:

curl -i -X POST -d '{"name":"C-3PO","type":"droid","year":1977}'
    http://localhost/my-rest-api/api/robots

HTTP/1.1 201 Created
Date: Wed, 12 Sep 2012 07:15:09 GMT
Server: Apache/2.2.22 (Unix) DAV/2
Content-Length: 75
Content-Type: text/html; charset=UTF-8

{"status":"OK","data":{"name":"C-3PO","type":"droid","year":1977,"id":"4"}}

Cobalah untuk memasukkan robot baru dengan nama robot yang sudah ada:

curl -i -X POST -d '{"name":"C-3PO","type":"droid","year":1977}'
    http://localhost/my-rest-api/api/robots

HTTP/1.1 409 Conflict
Date: Wed, 12 Sep 2012 07:18:28 GMT
Server: Apache/2.2.22 (Unix) DAV/2
Content-Length: 63
Content-Type: text/html; charset=UTF-8

{"status":"ERROR","messages":["The robot name must be unique"]}

Atau memperbarui robot dengan jenis yang tidak diketahui:

curl -i -X PUT -d '{"name":"ASIMO","type":"humanoid","year":2000}'
    http://localhost/my-rest-api/api/robots/4

HTTP/1.1 409 Conflict
Date: Wed, 12 Sep 2012 08:48:01 GMT
Server: Apache/2.2.22 (Unix) DAV/2
Content-Length: 104
Content-Type: text/html; charset=UTF-8

{"status":"ERROR","messages":["Value of field 'type' must be part of
    list: droid, mechanical, virtual"]}

Akhirnya, menghapus robot:

curl -i -X DELETE http://localhost/my-rest-api/api/robots/4

HTTP/1.1 200 OK
Date: Wed, 12 Sep 2012 08:49:29 GMT
Server: Apache/2.2.22 (Unix) DAV/2
Content-Length: 15
Content-Type: text/html; charset=UTF-8

{"status":"OK"}

Kesimpulan 

Sebagaimana telah kita lihat, mengembangkan RESTful API dengan Phalcon sangatlah mudah. Kemudian dalam dokumentasi kami akan menjelaskan secara rinci bagaimana menggunakan aplikasi mikro dan bahasa PHQL .

Terjemahan dari Tutorial Phalcon 3 : Membuat RESTful API Sederhana
http://docs.phalconphp.com/en/latest/reference/tutorial-rest.html