PHP Ionic Angular Phonegap AJAX Javascript CSS MySQL jQuery Forum


เพิ่มความสามารถ RESTful Services ใน CodeIgniter อย่างง่าย

22 July 2017 By
codeigniter restful

คำสั่ง การ กำหนด รูปแบบ ตัวอย่าง เทคนิค ลูกเล่น การประยุกต์ การใช้งาน เกี่ยวกับ codeigniter restful



เนื้อหาต่อไปนี้ จะมาแสดงตัวอย่างการใช้งาน RESTful Services ใน CodeIgniter เพิ่มเติม
ต่อจากบทความที่เคยอธิบายการใช้งานเบื้องต้นมาแล้ว สามารถย้อนไปดูบทความเก่าๆ ได้ที่
 
ใช้งาน RESTful Services ใน CodeIgniter ด้วย Rest Server 
http://www.ninenik.com/content.php?arti_id=702 via @ninenik
 
ภาคต่อ ใช้งาน RESTful Services ฟังก์ชั่นสำหรับ POST ข้อมูล 
http://www.ninenik.com/content.php?arti_id=703 via @ninenik
 
เนื่องจากเป็นเนื้อหาต่อเนื่องดังนั้น การใช้งานเบื้องต้น หรือการเตรียมพร้อมการใช้งานให้อ่านย้อนหลัง
ได้จากบทความด้านบน
 
เริ่มต้นในการทำ API ของเราคือ เราจะสร้างโฟลเดอร์ api > v1 ในโฟลเดอร์
apps > controllers ตามโครงสร้างตามรูปดังนี้
 
 

 
 
เราก็จะสามารถเรียกใช้งานผ่าน url ในรูปแบบดังนี้
 
/api/v1
 
การกำหนดเวอร์ชั่นของ api ช่วยให้เราสามารถยังใช้ api เวอร์ชั่นเดิมได้
และรองรับการพัฒนาเวอร์ชั่นใหม่ๆ เพื่อแยกส่วนของการใช้งานได้ชัดเจนขึ้น 
 
ในบทความนี้ เราจะจำลองข้อมูลจังหวัดในประเทศไทย จากฐานข้อมูลมาใช้ในการสร้าง
API รายการข้อมูล ประกอบรูปแบบการอธิบายและการประยุกต์ต่างๆ สามารถใข้ข้อมูลสำหรับ
ทดสอบดังนี้
 
--
-- Table structure for table `tbl_provinces`
--

CREATE TABLE IF NOT EXISTS `tbl_provinces` (
  `province_id` int(5) NOT NULL,
  `province_code` varchar(2) COLLATE utf8_unicode_ci NOT NULL,
  `province_name` varchar(150) COLLATE utf8_unicode_ci NOT NULL,
  `province_name_eng` varchar(150) COLLATE utf8_unicode_ci NOT NULL,
  `geo_id` int(5) NOT NULL DEFAULT '0'
) ENGINE=MyISAM AUTO_INCREMENT=78 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

--
-- Dumping data for table `tbl_provinces`
--

INSERT INTO `tbl_provinces` (`province_id`, `province_code`, `province_name`, `province_name_eng`, `geo_id`) VALUES
(1, '10', 'กรุงเทพมหานคร', 'Bangkok', 2),
(2, '11', 'สมุทรปราการ', 'Samut Prakan', 2),
(3, '12', 'นนทบุรี', 'Nonthaburi', 2),
(4, '13', 'ปทุมธานี', 'Pathum Thani', 2),
(5, '14', 'พระนครศรีอยุธยา', 'Phra Nakhon Si Ayutthaya', 2),
(6, '15', 'อ่างทอง', 'Ang Thong', 2),
(7, '16', 'ลพบุรี', 'Loburi', 2),
(8, '17', 'สิงห์บุรี', 'Sing Buri', 2),
(9, '18', 'ชัยนาท', 'Chai Nat', 2),
(10, '19', 'สระบุรี', 'Saraburi', 2),
(11, '20', 'ชลบุรี', 'Chon Buri', 5),
(12, '21', 'ระยอง', 'Rayong', 5),
(13, '22', 'จันทบุรี', 'Chanthaburi', 5),
(14, '23', 'ตราด', 'Trat', 5),
(15, '24', 'ฉะเชิงเทรา', 'Chachoengsao', 5),
(16, '25', 'ปราจีนบุรี', 'Prachin Buri', 5),
(17, '26', 'นครนายก', 'Nakhon Nayok', 2),
(18, '27', 'สระแก้ว', 'Sa Kaeo', 5),
(19, '30', 'นครราชสีมา', 'Nakhon Ratchasima', 3),
(20, '31', 'บุรีรัมย์', 'Buri Ram', 3),
(21, '32', 'สุรินทร์', 'Surin', 3),
(22, '33', 'ศรีสะเกษ', 'Si Sa Ket', 3),
(23, '34', 'อุบลราชธานี', 'Ubon Ratchathani', 3),
(24, '35', 'ยโสธร', 'Yasothon', 3),
(25, '36', 'ชัยภูมิ', 'Chaiyaphum', 3),
(26, '37', 'อำนาจเจริญ', 'Amnat Charoen', 3),
(27, '39', 'หนองบัวลำภู', 'Nong Bua Lam Phu', 3),
(28, '40', 'ขอนแก่น', 'Khon Kaen', 3),
(29, '41', 'อุดรธานี', 'Udon Thani', 3),
(30, '42', 'เลย', 'Loei', 3),
(31, '43', 'หนองคาย', 'Nong Khai', 3),
(32, '44', 'มหาสารคาม', 'Maha Sarakham', 3),
(33, '45', 'ร้อยเอ็ด', 'Roi Et', 3),
(34, '46', 'กาฬสินธุ์', 'Kalasin', 3),
(35, '47', 'สกลนคร', 'Sakon Nakhon', 3),
(36, '48', 'นครพนม', 'Nakhon Phanom', 3),
(37, '49', 'มุกดาหาร', 'Mukdahan', 3),
(38, '50', 'เชียงใหม่', 'Chiang Mai', 1),
(39, '51', 'ลำพูน', 'Lamphun', 1),
(40, '52', 'ลำปาง', 'Lampang', 1),
(41, '53', 'อุตรดิตถ์', 'Uttaradit', 1),
(42, '54', 'แพร่', 'Phrae', 1),
(43, '55', 'น่าน', 'Nan', 1),
(44, '56', 'พะเยา', 'Phayao', 1),
(45, '57', 'เชียงราย', 'Chiang Rai', 1),
(46, '58', 'แม่ฮ่องสอน', 'Mae Hong Son', 1),
(47, '60', 'นครสวรรค์', 'Nakhon Sawan', 2),
(48, '61', 'อุทัยธานี', 'Uthai Thani', 2),
(49, '62', 'กำแพงเพชร', 'Kamphaeng Phet', 2),
(50, '63', 'ตาก', 'Tak', 4),
(51, '64', 'สุโขทัย', 'Sukhothai', 2),
(52, '65', 'พิษณุโลก', 'Phitsanulok', 2),
(53, '66', 'พิจิตร', 'Phichit', 2),
(54, '67', 'เพชรบูรณ์', 'Phetchabun', 2),
(55, '70', 'ราชบุรี', 'Ratchaburi', 4),
(56, '71', 'กาญจนบุรี', 'Kanchanaburi', 4),
(57, '72', 'สุพรรณบุรี', 'Suphan Buri', 2),
(58, '73', 'นครปฐม', 'Nakhon Pathom', 2),
(59, '74', 'สมุทรสาคร', 'Samut Sakhon', 2),
(60, '75', 'สมุทรสงคราม', 'Samut Songkhram', 2),
(61, '76', 'เพชรบุรี', 'Phetchaburi', 4),
(62, '77', 'ประจวบคีรีขันธ์', 'Prachuap Khiri Khan', 4),
(63, '80', 'นครศรีธรรมราช', 'Nakhon Si Thammarat', 6),
(64, '81', 'กระบี่', 'Krabi', 6),
(65, '82', 'พังงา', 'Phangnga', 6),
(66, '83', 'ภูเก็ต', 'Phuket', 6),
(67, '84', 'สุราษฎร์ธานี', 'Surat Thani', 6),
(68, '85', 'ระนอง', 'Ranong', 6),
(69, '86', 'ชุมพร', 'Chumphon', 6),
(70, '90', 'สงขลา', 'Songkhla', 6),
(71, '91', 'สตูล', 'Satun', 6),
(72, '92', 'ตรัง', 'Trang', 6),
(73, '93', 'พัทลุง', 'Phatthalung', 6),
(74, '94', 'ปัตตานี', 'Pattani', 6),
(75, '95', 'ยะลา', 'Yala', 6),
(76, '96', 'นราธิวาส', 'Narathiwat', 6),
(77, '97', 'บึงกาฬ', 'buogkan', 3);

--
-- Indexes for dumped tables
--

--
-- Indexes for table `tbl_provinces`
--
ALTER TABLE `tbl_provinces`
  ADD PRIMARY KEY (`province_id`);

--
-- AUTO_INCREMENT for dumped tables
--

--
-- AUTO_INCREMENT for table `tbl_provinces`
--
ALTER TABLE `tbl_provinces`
  MODIFY `province_id` int(5) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=78;
 
 
หรือดาวน์โหลดได้ที่บทความ
 
ใช้ ajax ประยุกต์ดึงข้อมูล จังหวัด อำเภอ ตำบล รหัสไปรษณีย์ในประเทศไทย 
http://www.ninenik.com/content.php?arti_id=684 via @ninenik
 
จากนั้นให้เราสร้างไฟล์ Provinces.php ในโฟลเดอร์ apps > controllers > api > v1 
ตามโครงสร้างไฟล์ดังรูป

 

 
 
แล้วเพิ่มโค้ดดึงข้อมูลรายการจังหวัดในประเทศไทยดังนี้
 
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
require(APPPATH.'libraries/REST_Controller.php');
 
class Provinces extends REST_Controller
{
    public function index_get()
    {
        $this->response($this->db->get('tbl_provinces')->result());				
        // ดึงรายการทั้งหมด
    }
 
    public function index_post()
    {
        // สร้างรายการใหม่
    }
 
    public function index_put()
    {
        // แก้ไขรายการ
    }
 
    public function index_delete()
    {
        // ลบรายการ
    }
}
 
ดูผลลัพธ์ผ่านทางบราวเซอร์ ผ่าน url 
 
/api/v1/provinces
 
จะได้เป็น
 
 

 
 
ตัวอย่างข้างต้นเป็นการดึงฟิลด์ทั้งหมดพร้อมรายการข้อมูลทั้งหมดในตาราง tbl_provinces สร้างเป็น
REST API สำหรับ HTTP GET Request อย่างง่ายและรวดเร็ว
 
คำสั่ง 
 
$this->response($this->db->get('tbl_provinces')->result());
 
เราสามารถเพิ่มสถานะของ HTTP ได้ดังนี้
 
$this->response($this->db->get('tbl_provinces')->result(),200); // HTTP 200 OK
 
จากรูปแบบข้างต้น เราสามารถใช้ความสามารถของ Query Builder ใน Codeigniter มาใช้ในการจัดรูปแบบ
การแสดงข้อมูลจากฐานข้อมูลได้ 
    ทบทวนการใช้งาน query builder ได้ที่บทความ
 
ทบทวนการใช้งาน query builder เพิ่มเติม สำหรับการ select ข้อมูล 
http://www.ninenik.com/content.php?arti_id=675 via @ninenik
 
เรามาดูการประยุกต์เพิ่มเติมกัน 
สมมติว่าเราต้องการแสดงเฉพาะข้อมูลของจังหวัดที่มี province_id ที่เราต้องการ ผ่านการเรียกใช้งาน
 
/api/v1/provinces/1
 
เราก็สามารถใช้การจัดการ segments ของ URI Class มาจัดการ แยก url string ออกเป็นส่วนๆ เพื่อนำไปใช้งาน
อย่างเช่น
 
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
require(APPPATH.'libraries/REST_Controller.php');
 
class Provinces extends REST_Controller
{
	public function index_get()
	{
		echo "<pre>";
		print_r($this->uri->segment_array());
		echo "</pre>";
		exit;
	}

}
 
ผลที่ได้ก็จะเป็น
 
Array
(
    [1] => api
    [2] => v1
    [3] => provinces
    [4] => 1
)
 
ค่าที่เราต้องการนำไปใช้งานก็คือค่า segment ตัวที่ 4 ซึ่งก็จะหมายถึง province_id ที่ 1
พอเราใช้งานร่วมกับ query builder ก็จะได้เป็น
 
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
require(APPPATH.'libraries/REST_Controller.php');
 
class Provinces extends REST_Controller
{
	public function index_get()
	{
		if($this->uri->segment(4)){
			$query =  $this->db->get_where("tbl_provinces",array('province_id'=>$this->uri->segment(4)));
		}else{
			$query =  $this->db->get('tbl_provinces');
		}
		$this->response($query->result());
	}

}
 
REST API ก็จะแสดงเฉพาะรายการ province_id เท่ากับ 1 มาแสดง ดังรูป
 
 

 
 
ต่อจากตัวอย่างด้านบน และสมมติว่า เราต้องการให้สามารถที่จะเลือกฟิลด์ข้อมูลที่ต้องการแสดงได้
อย่างตัวอย่างข้างต้น เป็นการไปดึงทุกๆฟิลด์ข้อมูลของรายการนั้นๆมาแสดง แต่ถ้าเราต้องการเฉพาะฟิลด์ข้อมูล
ที่สนใจ ก็สามารถประยุกต์เพิ่มเติมได้ โดยเรียกผ่าน url
 
/api/v1/provinces?fields=province_id,province_name
 
การทำงานของ url ข้างต้นคือ แสดงรายการจังหวัดทั้งหมด โดยแต่ละจังหวัดให้แสดงเฉพาะข้อมูลของฟิลด์ที่กำหนด
ซึ่งก็คือ province_id และ province_name
 
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
require(APPPATH.'libraries/REST_Controller.php');
 
class Provinces extends REST_Controller
{
	public function index_get()
	{
		if($this->get('fields') && $this->get('fields')!=""){
			$this->db->select($this->get('fields'));
		}
		if($this->uri->segment(4)){
			$query =  $this->db->get_where("tbl_provinces",array('province_id'=>$this->uri->segment(4)));
		}else{
			$query =  $this->db->get('tbl_provinces');
		}
		$this->response($query->result());		
	}

}
 
สังเกตว่าเราได้เพิ่ม query string ที่ชื่อ fields และมีค่าเป็น province_id,province_name เป็นฟิลด์ข้อมูล
ที่เราต้องการแสดง แล้วใช้ คำสั่ง query builder จัดรูปแบบการดึงข้อมูลจากฐานข้อมูลเฉพาะฟิลด์ที่ต้องการ
ผลที่ได้ก็จะเป็นดังรูป

 

 
 
จากรูปแบบโค้ดด้านบนเราสามารถที่แสดงรายการเดียว พร้อมกับเรียกดูเฉพาะฟิลด์ได้ เช่น
 
/api/v1/provinces/1?fields=province_id,province_name
 
จะได้เป็น
 
 
 
 
ต่อไปใช้หลักการคล้ายๆ กัน สมมติเราต้องการแสดงช้อมูลแค่ 5 รายการ หรือต้องการเลือกที่จะแสดงข้อมูล
ตามค่า limit โดยกำหนดการเรียกใช้ผ่าน url ดังนี้
 
/api/v1/provinces/?fields=province_id,province_name&limit=5
 
รูปแบบโค้ดที่ใช้งาน
 
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
require(APPPATH.'libraries/REST_Controller.php');
 
class Provinces extends REST_Controller
{
	public function index_get()
	{
		if($this->get('fields') && $this->get('fields')!=""){
			$this->db->select($this->get('fields'));
		}
		if($this->get('limit') && $this->get('limit')!=""){			
			$this->db->limit((int) $this->get('limit'));
		}		
		if($this->uri->segment(4)){
			$query =  $this->db->get_where("tbl_provinces",array('province_id'=>$this->uri->segment(4)));
		}else{
			$query =  $this->db->get('tbl_provinces');
		}		
		$this->response($query->result());
	}

}
 
ผลลัพธ์ที่ได้ จะได้เป็น

 

 
 
ปรับโค้ดเพิ่มเติมให้รองรับการแสดงรายการหน้าที่ต้องการ ผ่านรูปแบบ url
 
/api/v1/provinces/?fields=province_id&limit=5&page=2
 
จะได้รูปแบบโค้ดเป็น
 
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
require(APPPATH.'libraries/REST_Controller.php');
 
class Provinces extends REST_Controller
{
	public function index_get()
	{
		if($this->get('fields') && $this->get('fields')!=""){
			$this->db->select($this->get('fields'));
		}
		if($this->get('limit') && $this->get('limit')!=""){	
			if($this->get('page') && $this->get('page')!=""){	
				$offset_page = ((int) $this->get('page')-1)*(int) $this->get('limit');
				$this->db->limit((int) $this->get('limit'),$offset_page);
			}else{
				$this->db->limit((int) $this->get('limit'));
			}
		}		
		if($this->uri->segment(4)){
			$query =  $this->db->get_where("tbl_provinces",array('province_id'=>$this->uri->segment(4)));
		}else{
			$query =  $this->db->get('tbl_provinces');
		}		
		$this->response($query->result());
	}

}
ผลลัพธ์ที่ได้

 

 
 
ปรับโค้ดเพิ่มเติมให้รองรับการเรียงข้อมูลตามกำหนด ผ่านรูปแบบ url
 
/api/v1/provinces/?limit=5&sort=province_id desc,province_name asc
 
จะได้รูปแบบโค้ดเป็น
 
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
require(APPPATH.'libraries/REST_Controller.php');
 
class Provinces extends REST_Controller
{
	public function index_get()
	{
		if($this->get('fields') && $this->get('fields')!=""){
			$this->db->select($this->get('fields'));
		}
		if($this->get('sort') && $this->get('sort')!=""){	
			$this->db->order_by($this->get('sort'));
		}				
		if($this->get('limit') && $this->get('limit')!=""){	
			if($this->get('page') && $this->get('page')!=""){	
				$offset_page = ((int) $this->get('page')-1)*(int) $this->get('limit');
				$this->db->limit((int) $this->get('limit'),$offset_page);
			}else{
				$this->db->limit((int) $this->get('limit'));
			}
		}		
		if($this->uri->segment(4)){
			$query =  $this->db->get_where("tbl_provinces",array('province_id'=>$this->uri->segment(4)));
		}else{
			$query =  $this->db->get('tbl_provinces');
		}		
		$this->response($query->result());
	}

}
 
ผลลัพธ์ที่ได้

 

 
 
จะเห็นว่าผลลัพธ์ล่าสุด มีการเรียงรายการจาก province_id จากค่ามากไปน้อย นั้นก็คือ province_id 
เท่ากับ 77 ไล่ลงมาเรื่อยๆ จนครบ 5 รายการที่ลำดับที่ 73
 
สำหรับกรณีตัวอย่างข้าง ถ้าเกิดว่าผู้ใช้งานกำหนดค่ามั่วๆ เข้ามา ก็อาจจะทำให้คำสั่งการคิวรี่ error ขึ้น
และ CodeIgniter ก็จะไปเรียกหน้าเพจแสดง error ของการใช้งาน db มาแสดง เพื่อป้องกันปัญหาเบื้องต้น
นั้น ให้เราปิดการแสดง หน้าเพจ error นั้น แล้วใช้วิธีการส่งค่า header เป็น BAD Request กลับมาแทนด้วย
status code 400  สามารถดูอ้างอิง HTTP Status Codes เพิ่มเติมได้ที่ลิ้งค์
 
http://www.restapitutorial.com/httpstatuscodes.html
 
คำสั่งปิดการแสดงเพจ error ของ db
 
$this->db->db_debug = false;
 
การกำหนด BAD Request สามารถกำหนดได้ดังนี้
 
$this->response(NULL, REST_Controller::HTTP_BAD_REQUEST);
 
หรือ
 
$this->response(NULL, 400);
 
มาดูตัวอย่างโค้ดเบื้องต้นอย่างง่ายทั้งหมดแบบเต็ม
 
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
require(APPPATH.'libraries/REST_Controller.php');
 
class Provinces extends REST_Controller
{
	public function index_get()
	{
		$this->db->db_debug = false;		
		if($this->get('fields') && $this->get('fields')!=""){
			$this->db->select($this->get('fields'));
		}
		if($this->get('sort') && $this->get('sort')!=""){	
			$this->db->order_by($this->get('sort'));
		}				
		if($this->get('limit') && $this->get('limit')!=""){	
			if($this->get('page') && $this->get('page')!=""){	
				$offset_page = ((int) $this->get('page')-1)*(int) $this->get('limit');
				$this->db->limit((int) $this->get('limit'),$offset_page);
			}else{
				$this->db->limit((int) $this->get('limit'));
			}
		}		
		if($this->uri->segment(4)){
			$query =  $this->db->get_where("tbl_provinces",array('province_id'=>$this->uri->segment(4)));
		}else{
			$query =  $this->db->get('tbl_provinces');
		}		
		if($query){
			$this->response($query->result());				
		}else{
			$this->response(NULL, REST_Controller::HTTP_BAD_REQUEST);
		}	

	}

}
 
การกำหนดรูปแบบโค้ดเบื้องต้นด้านบน ช่วยป้องกันกรณีผู้ใช้ส่งค่าหรือเรียกใช้รูปแบบ API ผ่าน url
ไม่ถูกต้อง ทำให้การคิวรี่ข้อมูลไม่ทำงาน และเราส่งกลับ HTTP status code เป็น BAD Request โดยไม่มี
ข้อความแจ้งใดๆ 
 
มาดูสมมติเราลองเรียกแบบใส่ค่าไม่ถูกต้องดู เช่น ระบุฟิลด์ที่ไม่มีอยู่จริงเข้าไป ตามการเรียกใช้ url ดังนี้
 
/api/v1/provinces/?fields=provinc
 
เนื่องจากตาราง tbl_province ของเราไม่มีฟิลด์ที่ชื่อ provinc  ผลลัพธ์ที่ได้ ค่าไม่มีการส่งค่าใดๆ กลับมา
และขึ้นสถานะ HTTP เป็น BAD Request ดังรูป

 

 
 
ในการใช้งานจริง เราอาจจะปรับแต่งหรือมีการตรวจสอบค่าต่างๆ เพิ่มเติมมากกว่านี้ก็ได้ ขึ้นกับการนำไป
ประยุกต์ใช้งาน เช่น กรณี BAD Request เราอาจจะมีการส่งข้อความ error กลับมาด้วยก็ได้ อย่างเช่น
แจ้งว่าไม่มีฟิลด์ข้อมูลที่กำลังเรียกดูข้อมูล เหล่านี้เป็นต้น
 
อย่างไรก็ดี เนื้อหา RESTful Services ใน CodeIgniter ยังไม่จบเท่านี้ รอติดตามเพิ่มเติมในตอนหน้า

 




อ่านต่อที่บทความ









เนื้อหาที่เกี่ยวข้อง



Tags:: codeigniter restful




เนื้อหาพิเศษ เฉพาะสำหรับสมาชิก

กรุณาล็อกอิน เพื่ออ่านเนื้อหาบทความ

ยังไม่เป็นสมาชิก

สมาชิกล็อกอิน



หริอ สมัครสมาชิก และล็อกอิน ด้วย Facebook



อย่าลืมกด Like กด Share เป็นกำลังใจ ในการสร้างบทความใหม่ๆ น่ะครับ


URL สำหรับอ้างอิง