[Web API] Tạo PHP web service cho ứng dụng mobile client

Hello,

Nhân đọc bài viết của các bác trên một blog nọ luận bàn về một lập trình viên backend, frontend và fullstack với những kỹ năng cần có. Nguồn: xxx.Bạn có thể lên Google search theo keyword như: fullstack developer meaning,jobs,salary…so on. Tớ không trích nguồn vì sợ mang tính chất PR cho blog đó hơn là chia sẻ quan điểm cá nhân. Nội dung bài viết đó và các kỹ năng đề cập thì nhiều lắm, tớ đọc thì vừa cảm nhận vừa suy diễn với công việc của một mobile developer. Tớ chú ý đến từ “fullstack“, theo bạn một lập trình viên ứng dụng di động(gọi tắt là LTV mobile) thế nào thì được gọi là “điên nước đầy đủ“(p/s: fullstack word translation) ????

Khoan bàn đến LTV mobile đó phải thành thạo ít nhất một ngôn ngữ lập trình mobile hiện thời như iOS(Swift),Android,Window phone,Xamarin…, phải có soft skills (p/s: search theo hint này eada một đống: soft skills the software developer’s life manual), team leadership,…blah,blah.

OK, điều tớ muốn nói ở đây là nhìn một cách hệ thống việc ứng dụng của bạn chỉ đóng vai trò client hay nói cách khác là frontend, tương tác trực tiếp với người dùng. Theo chiều ngược lại,người dùng thao tác với ứng dụng bạn viết ra để làm một điều tuyệt vời nào đó,ở một nơi nào đó mà không phải ngay trên ứng dụng của bạn??

Mô hình phổ biến hiện nay là các tác vụ,chức năng,lưu trữ,xử lý,đa nhiệm… sẽ được đưa toàn bộ lên Cloud – Server. Nghĩa là ứng dụng của bạn viết ra để làm cầu nối (đúng theo cả nghĩa đen và nghĩa bóng) vô cùng tuyệt vời giữa Cloud – Server và End Users. Kiểu kiểu như này:

Hôm nay tớ sẽ chia sẻ chút về 3 cái cục www màu xanh và vô số cục đên xì có gắn mác Server Stack.

Như ở trên tớ đã nói về nhiệm vụ của Server rồi,giờ sẽ chỉ nói về Webservice(có thể gọi là backend) – thao tác với Database server,xử lý các tác vụ mà client mobile gửi đến rồi sau đó phản hồi lại dưới dạng các cấu trúc NoSQL như JSON,BJSON hay XML. Ở đây tớ lựa chọn ngôn ngữ PHP vì những lý do sau:

– Dễ tiếp cận.

– Dễ hiểu cho những bạn newbie như tớ. Còn về performance hay multi-tasks thì có lẽ Node.js là sự lựa chọn tối ưu,hah?

Bắt đầu với việc chạy một PHP page trên server thật thì trước mắt cần run-test loop trên server giả lập(localhost) cái đã. Có rất nhiều tools cho phép bạn làm điều này, ví dụ như trên window có:

 Wamp Server

XAMPP

Cái tớ đang sử dụng là AMPPS đang chạy trên nền tảng MacOS. Link tải và introduction ở đây: http://www.ampps.com

Về configuration thì cũng khá đơn giản, bạn cần đưa toàn bộ source vào thư mục: /Applications/AMPPS/www

Xong xuôi thì các bạn chạy ứng dụng:

Tiếp theo click vào nút Start bên Apache để kích hoạt localhost và nút Start bên MySQL để kích hoạt db server nhé. Sau khi đã start thì các bạn vào trình duyệt và gõ http://localhost sẽ list ra toàn bộ thư mục của bạn đã được giả lập như nằm trên server như này:

 Tớ tạo 1 thư mục có tên là testExample,trong đó tớ tạo tiếp 1 sub folder với tên là config và sau cùng là 1 PHP file với tên là systemConfig.php. File này có nhiệm vụ mở cổng giao tiếp với MySQL và định nghĩa các HTTP statu codes trả về khi bạn thao tác với server (link tham khảo về chúng đây: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes)

OK,cứ tạm thời tạo ra thư mục và file như vậy.Giờ là lên xem MySQL server thế nào đã. Với các bạn đã có kinh nghiệm lập trình web thì chẳng xa lạ gì nữa rồi. Các bạn gõ lên trình duyệt link: http://localhost/phpmyadmin

Các bạn sẽ thao tác trên đó để tạo DB,tạo bảng,insert dữ liệu, sử dụng SQL statements để truy vấn…blah,blah, những cái này chắc khỏi cần guide nữa.

Ảnh trên tớ tạo 1 db tên là xxx, 1 table đơn giản cũng tên xxx với 2 trường đơn giản gồm: image_id (lưu id,tự động tăng) và image_url(lưu url của image lấy từ trên Google về). Viết 1 câu lệnh SQL statement đơn giản: Select * from xxx thì nó trả ra như này:

 Aloha, giờ viết code nào 

Các bạn vẫn nhớ file systemConfig.php tớ vừa tạo chứ?? Tớ tạo 1 class với 1 biến dbConnect như sau:

<?php

class systemConfig {
var $dbConnect;

}

>

Tiếp theo là viết các hàm contructor và distructor ( cả 2 đều optional nhé)

function __construct(){

}

function __destruct() {
$this->dbConnect->close();
}

function connectDB(){
$this->dbConnect = new mysqli(‘localhost’, ‘root’, ‘mysql’, ‘xxx’);
if($this->dbConnect->connect_errno){
return null;
}else{
return $this->dbConnect;
}
}

Viết tiếp 1 function có tên connectDB() để kết nối đến database với các thông số:

‘localhost’: tên IP cần trỏ đến, ở đây chính là localhost.

‘root’, ‘mysql’: user và pass try cập vào MySQL (default của php myAdmin).

‘xxx’: tên database bạn tạo.

Next, viết hàm định nghĩa HTTP status codes với tham số truyền vào là status code,đầu ra là status description:

function getStatusCodeMeeage($status){
$codes = Array(
100 => ‘Continue’,
101 => ‘Switching Protocols’,
200 => ‘OK’,
201 => ‘Created’,
202 => ‘Accepted’,
203 => ‘Non-Authoritative Information’,
204 => ‘No Content’,
205 => ‘Reset Content’,
206 => ‘Partial Content’,
300 => ‘Multiple Choices’,
301 => ‘Moved Permanently’,
302 => ‘Found’,
303 => ‘See Other’,
304 => ‘Not Modified’,
305 => ‘Use Proxy’,
306 => ‘(Unused)’,
307 => ‘Temporary Redirect’,
400 => ‘Bad Request’,
401 => ‘Unauthorized’,
402 => ‘Payment Required’,
403 => ‘Forbidden’,
404 => ‘Not Found’,
405 => ‘Method Not Allowed’,
406 => ‘Not Acceptable’,
407 => ‘Proxy Authentication Required’,
408 => ‘Request Timeout’,
409 => ‘Conflict’,
410 => ‘Gone’,
411 => ‘Length Required’,
412 => ‘Precondition Failed’,
413 => ‘Request Entity Too Large’,
414 => ‘Request-URI Too Long’,
415 => ‘Unsupported Media Type’,
416 => ‘Requested Range Not Satisfiable’,
417 => ‘Expectation Failed’,
500 => ‘Internal Server Error’,
501 => ‘Not Implemented’,
502 => ‘Bad Gateway’,
503 => ‘Service Unavailable’,
504 => ‘Gateway Timeout’,
505 => ‘HTTP Version Not Supported’
);

return (isset($codes[$status])) ? $codes[$status] : ”;
}

Hàm trả về response khi client request:

function sendResponse($status = 200, $body = ”, $content_type = ‘text/html’)
{
$status_header = ‘HTTP/1.1 ‘ . $status . ‘ ‘ . $this->getStatusCodeMeeage($status);
header($status_header);
header(‘Content-type: ‘ . $content_type);
echo $body;
}

Vậy là xong việc configuration,bước tiếp theo là viết code để thao tác thực sự với db. Tớ viết thêm 1 class có tên là imageResourcesDAO.php,class có nhiệm vụ lấy ra các bản ghi ở table xxx trong db và trả ra dưới dạng JSON:

<?php

include(“../testExample/config/systemConfig.php”);
class imageResources {
private $dbReference;
var $dbConnect;
var $result;

/**
*
*/
function __construct(){

}

function __destruct(){

}

//get images
function getAllImageResource(){
$this->dbReference = new systemConfig();
$this->dbConnect = $this->dbReference->connectDB();
if ($this->dbConnect == NULL) {
$this->dbReference->sendResponse(503,'{“error_message”:’.$this->dbReference->getStatusCodeMeeage(503).’}’);
}else{

$sql = “SELECT * FROM xxx”;
$number_per_page = $_POST[“number_per_page”];
$page = ($_POST[“page”]-1)*$number_per_page +1;
$page_next = $_POST[“page”]*$number_per_page;
//echo “$page”;

if ($page != NULL && $number_per_page != NULL) {
//echo “viva for”;
$sql = “SELECT * FROM xxx WHERE image_id BETWEEN $page AND $page_next”;
}/*else{
echo “0 results”;
return;
}*/
$this->result = $this->dbConnect->query($sql);
if($this->result->num_rows > 0){
// output data of each row
$resultSet = array();
while($row = $this->result->fetch_assoc()) {
$resultSet[] = $row;
}
$this->dbReference->sendResponse(200,'{“items”:’.json_encode($resultSet).’}’);
}else{
//echo “0 results”;
$this->dbReference->sendResponse(200,'{“items”:null}’);
}

}
}
}

>

$_POST[“number_per_page”]  $_POST[“page”] là 2 tham số gửi data lên server theo dạng POST. Về làm việc với POST hay GET các bạn tham khảo ở đây nhé: http://stackoverflow.com/questions/3477333/what-is-the-difference-between-post-and-get

Ngắn gọn thì có 2 cách để pass data lên web service:

– GET: params là 1 phần của URL hay còn gọi là query string.

– POST: params là 1 phần của body request.

Chú ý đến câu lệnh sql: SELECT * FROM xxx WHERE image_id BETWEEN $page AND $page_next –> câu lệnh này trả ra số lượng items theo số page và số item trên 1 page, sử dụng để load more trên ứng dụng mobile sau này. Mọi dòng code đều rất trong sáng và dễ hiểu phải không? 😉

Các bạn có thể mở rộng hơn db bằng cách thêm các table và viết các hàm để truy vấn,insert,update,delete nhé,ở tut này tớ chỉ code đơn giản demo thôi.

Almost done! Cuối cùng tạo thêm 1 class để gọi các functions strong class DAO kia thôi. Tạo class có tên imageRequest.php với nội dung:

<?php

include(“../testExample/imageResourcesDAO.php”);
$viva = new imageResources();
$viva->getAllImageResource();

>

Giờ là lúc các bạn test sản phẩm của mình. Với tớ thì tớ hay sử dụng REST – plugin của Chrome cho phép send request  theo cả POST or GET đến server. Đây là các thao tác nhé, bạn sẽ nhìn thấy 2 tham số được đưa lên theo phương thức POST (lấy 20 bản ghi ở page 1):

 Và theo sau là kết quả:

Nói thêm chút về việc đưa lên môi trường thật.

– Về db thì bạn có thể export ra dạng file .sql rồi import lên hosting bạn đăng ký nhé.

– Về config lại một số thông tin như tên IP, user- pass SQL server, include page… thì cũng không khó lắm đâu, vọc 1 tẹo là được thôi, thay đổi trong systemConfig.php là OK.

Lần sau tớ sẽ viết 1 bài tích hợp web api vừa tạo với mobile client(iOS) nhé!

Have fun!


Integrating machine learning with Bladder Image Segmentation