jQueryTips by Tee++;

  • Home
  • Videos
  • jQueryTips's Fans

Coding like playing a piano.

Subscribe RSS

Search

Search

Sponsored

jQueryTips on Social

Followers

hide
Chainnnn Pang25441 Dexteri@n Ton KanexKane Supachai JustDoIt Rut petchy Tophit anndrew Webmaster

Categories

hide
  • Programing
  • Database
  • Framework
  • Mobile Development
    • Titanium Mobile
    • PhoneGap
  • Life

Tag Cloud

hide
PHP JavaScript MySQL XML Mobile jQuery CodeIgniter Hash php xml Debug Library Zend API Events Plugins Facebook Basic Registration Tool Twitter Search Swath Performance ffmpeg YouTube Web Service Yahoo! NoSQL MongoDB PhoneGap

Recent Posts

hide
  • ใครๆ ก็มี Utils เอางี้เราเพิ่ม Utils ให้กับ CodeIgniter กันบ้าง
  • แนะนำ JS.Class (A JavaScript class library)
  • PHP กับ OOP มาปูพื้นฐานกันเสียใหม่ก่อน
  • ประกาศข่าวสารจาก Admin
  • JSFIDDLE สุดยอด Tools สำหรับการ Debug การเขียนตัวอย่างโคด
  • Titanium Mobile + HTML + Native Scrolling
  • HTML to PDF ตัวไหนดี วันนี้ผมมีคำตอบ ...
  • ทำความรู้จักกับ JavaScript Pattern ในเชิงลึก
  • ผมบอกคุณแล้ว .... คนโง่ก็ Code ได้
  • วันนี้ มาออกแบบ Web Service ด้วย PHP กันเถอะ (CodeIgniter Version)

Recent Comments

hide
  • เยดดดด
  • มีตัวอย่าง CI แบบ เพียว ๆ ไหมครับ
  • ขอบคุณมากครับ เห็นแนวทางได้ชัดขึ้นจากตอนแรก ที่งงไปหมด ไม่รู้อะไรเป็นอะไร
  • ขอบคุณมากเลยครับท่าน....แหม่เพิ่มกำลังใจให้ผมได้เยอะเลย ตอนนี้กำลังฝึกงานอยู่ที่แห่งนึงในหาดใหญ่ พร้อมเด็กจากอีกสถาบันนึง 3 คน เราคิดว่าเรา…
  • Very good blog, I really like ~

Links

hide
  • OSCOOL
  • Architeture & Performance
  • Video and TV
  • Appcelerator
  • PhoneGap
  • Home
  •  » Blogs

วันนี้ มาออกแบบ Web Service ด้วย PHP กันเถอะ (CodeIgniter Version)

Nov 12, 2011 1:41:31 AM | 4 Comments | in Programing | API, Web Service, Zend

โอ้โห ไม่ได้อัพเดทบล็อกนี้ (มีบล็อกเดียว) มานานมากๆ เผลอแป๊บเดียว 4 เดือนเข้าไปแล้ว ก็มันขี้เกียจนี่หว่า ไว้จะทำ Screen Cast แทนไม่รู้จะลำบากขึ้นมั้ย 555

เอาล่ะ ไหนๆ ก็อัพ แล้ว เอาเรื่องที่หาอ่าน บทความภาษาไทย ไม่ค่อยได้ดีกว่า เรื่องของ "Web Service"  ครับ ปกติส่วนมากจะมีแต่บทความวิธีใช้ แต่ว่า วันนี้ผมจะมาเขียน บทความ "วิธีทำ" กันดีกว่า

สมัยนี้ หนียังไงก็หนีไม่พ้น กับการต้องเข้าไปยุ่งกับ API ของเว็บบิ๊กๆ ทั้งหลาย ซึ่งแต่ละเว็บก็มีการใช้ Protocol ต่างกันไป ถ้ายิ่ง บิ๊กมาก ก็จะมี Protocol ให้ใช้แทบจะครบ

มีทั้ง RESTful, XML-RPC, JSON-RPC, SOAP, etc. ซึ่งลงท้ายทุกตัวทำงานเหมือนกันหมด คือใช้ติดต่อ ระหว่าง โปรแกรม ซึ่งตอนนี้ API ของเว็บทุกเว็บ อย่างน้อยจะต้องมี  1 protocol คือ REST เพราะว่ามันง่ายกับ Developer ในการติดต่อ แล้วก็เขียนเชื่อมไป จะว่า XML-RPC, JSON-RPC ก็ต้องถือว่า เป็น REST ด้วยเหมือนกันแหละ เพียงแต่ Response Format ต่างออกไป

เอาล่ะ ทฤษฎีอาจจะไม่ค่อยแน่น แต่ปฎิบัติ ผมพอไหว  555

วันนี้เราจะมาออกแบบ ชุด API ของ REST กัน โดยที่โจทย์ของเรามีดังนี้

1. API จะต้อง Authen จากโปรแกรมเชื่อมใช้งานได้

2. Structure ต้องเป็นระเบียบสามารถเพิ่ม ชุด function ได้ง่าย

3. Response ต้องออกได้ทั้ง XML และ JSON

4. ต้องมี Failed Message  ในกรณีที่ API ไม่สามารถทำงานได้สมบูรณ์

อุปกรณ์เครื่องครัวที่ต้องเตรียมมา

1. CodeIgniter ตัวนี้ใช้เป็น Base Render MVC เฉยๆ จะมีไม่มีก็ไม่ว่ากัน เอา Structure ตามถนัด

2. Zend_Rest_Server ตัวนี้ก็เหมือน เนื้อสัน ไม่มีก็ทำ เสต๊ก ไม่ได้

3. Zend_Json ตัวนี้เอาไปแปลง Response Format  กลับไป กลับมาระหว่า XML -> JSON

เอาล่ะ มาเริ่มกันเลย....

ก่อนอื่นเราต้องมี File Bootstrap ของ API คือตัวกลางนั่นแหละ เวลาที่ ใครเรียกจะต้องมาที่ไฟล์นี้ก่อนซึ่งตัวนี้ผมใช้ Controller นั้น CI  มาทำ

โดยในไฟล์นี้ผมตั้งชื่อ Controller ว่า Rest.php

 

<?php

class Rest extends CI_Controller {

	public static $server;
	
	private $_methods = array('blogs');
	
	public function __construct()
	{
		parent::__construct();
		
		// load zend reset server class

		
		require_once('Zend/Rest/Server.php');
		self::$server = new Zend_Rest_Server();
		
	}
	
	public function _remap($method, $attrs)
	{
		// check existing api methods
		if (!in_array($method, $this->_methods)) {
			die('API is not exists');
		}
		
		// if having specific method
		if (method_exists($this, $method)) {
			call_user_func_array(array($this, $method), $attrs);
		}
		else {		
			$call = "service_{$method}";
			$this->load->model('services/'.$call);
			self::$server->setClass($call);
		}
		
		// keep response
		self::$server->returnResponse(true);
		$xmlstr = self::$server->handle();
				
		// response format
		$format = $this->input->get_post('format');
		if (strcasecmp($format, 'json') == 0)
		{	
			// format output to valid structure
			$dom = new DOMDocument('1.0');
			$dom->preserveWhiteSpace = false;
			$dom->formatOutput = true;
			$dom->loadXML($xmlstr);
			
			// now we have valid format
			$xmlstr = $dom->saveXML();
				
			// zend not provide attribute, so we change to the code below
			$this->load->loadClass('Zend_Json');
			$response = Zend_Json::fromXml($xmlstr, true);		
			
			header('Content-Type:application/javascript;charset=' . config_item('charset'));
			echo Zend_Json::prettyPrint($response); exit(0);
		}
		
		// return XML format
		header('Content-Type:text/xml; charset='.config_item('charset'));
		echo $xmlstr;
	}
		
}

?>

 

ไฟล์นี้ก็มีประมาณนี้ครับ โดยแต่ละ method มีการทำงาน คร่าวๆ ดังนี้

method __construct

ส่วนนี้จะเป็นส่วนของการ include Zend_Rest_Server เข้ามาใช้งาน กับโหลด helper บางตัวเข้ามา (ผมจะขยายงาน helper ตัวนี้ทีหลัง)

method _remap

ส่วนนี้เป็น คล้ายๆ magic method ใน CI คือ เอาง่ายๆ มันเหมือน __call ใน class ปกติ ที่เวลาเราเรียก method อะไรมันจะเข้ามาที่นี่ก่อน นั่นแหละ

ส่วนการทำงานของมันก็คือ เป็นตัวรับ method ที่ user เข้ามาใช้งาน จุดสำคัญช่วงแรกอยู่ที่โคดตรงช่วงนี้

 

$call = "service_{$method}";
$this->load->model('services/'.$call);
self::$server->setClass($call);

 

จะเป็นตัวรับ method ว่า user call อะไรมาเช่น  blogs, albums, friends

ก็จะไปเรียก model ที่อยู่ตาม path แบบนี้

/application/models/services/service_blogs.php

จากนั้นก็เอา methods ใน service_blogs ว่ามองเป็น method ของชุด API blogs

ส่วนท้ายๆ มันคือกันทำ  format ระหว่าง xml, json ค่อยๆ ไล่โคดเอาแล้วกันนะครับ 

 

ทีนี้มาดูในส่วนของ service_blogs.php  กันว่า เรามีอะไรบ้าง

 

<?php

class service_blogs extends CI_Model {

	public function __construct()
	{
		parent::__construct();
	}
	
	public function GetItems($page=1, $limit=20, $sort="created_at-desc", $criteria=array())
	{
		// implement
		
		return array();
	}
	
	public function GetItem($id)
	{
		// implement
		
		return array();
	}
	
}

?>

 

เราจะมี methods ที่รอการ implement เรียงอยู่ครับ ซึ่งถ้าเราทำ สองไฟล์นี้จบแล้ว เราจะสามารถเรียกแบบนี้ได้

http://xxx.com/api/rest/blogs?method=GetItem&page=1&limit=20

โดยถ้าเราแยกชิ้นของ URL ออกมาจะมองเป็น โปรแกรมได้ดังนี้

1. rest = controller (CI)

2. blogs = model (models/services/service_blogs.php)

3. method:GetItems = method นึง ใน class ของ service_blogs

4. &page=1&limit=20 = arguments ของ method นั้นๆ

ที่เหลือ เราก็แค่ implement ลงไป Zend_Rest_Server จะจัดการทำ ให้ออกมาเป็น XML เอง

 

ทีนี้เราลองมา Implement ดูสักนิด ที่ method GetItem แล้วกัน สมมุตผมโคดลงไปแบบนี้

 

public function GetItem($id)
	{
		return array(
			'response' => array(
				'id' => $id,
				'message' => "You are calling blogs:GetItem with parameter id = ".$id
			)
		);
	}

 

แล้วผมมาลองเรียกแบบนี้

http://xxx.com/api/rest/blogs?method=GetItem

สิ่งที่ผมจะได้กลับมาก็คือ

เพราะว่าอะไรครับ ?

เพราะว่า id ผมเป็น field บังคับ Zend_Rest_Server จะมาเป็นตัวจัดการตรงนี้เอง แต่ถ้าผมเขียนโคดใหม่เป็น

 

public function GetItem($id=123)
	{
		return array(
			'response' => array(
				'id' => $id,
				'message' => "You are calling blogs:GetItem with parameter id = ".$id
			)
		);
	}

 

สังเกตุตรง id=123  นะครับ

ผลลัพธ์ที่ได้ ก็จะผิดกัน จะเหมือนกับผมเรียกไปด้วย URL

http://xxx.com/api/rest/blogs?method=GetItem&id=123 นั่นแหละครับ ตามภาพด้านล่าง

 

 

เอาล่ะ ทีนี้เราลองมาทำการ validate ชุดของ api แบบง่ายๆกันดูนะครับ ผมจะเพิ่มโคดอีกหน่อย ดังนี้

 

public function GetItem($id=123)
	{
	 	$username = $this->input->get_post('username');
	 	$password = $this->input->get_post('password');
	 	
	 	if (strcmp($username, 'Teepluss') != 0 || strcmp($password, '123') != 0) {
	 		throw new Exception('Sorry, User is exists our database.');
	 	}
	 	
	 	
		return array(
			'response' => array(
				'id' => $id,
				'message' => "You are calling blogs:GetItem with parameter id = ".$id
			)
		);
	}

 

จะเห็นได้ว่า ผมมีการร้องขอ ให้กรอก  username + password เข้ามาแล้ว ที่ผมไม่เอาใส่เป็น parameters ของ method เพราะจะทำให้ดูว่ามันจะเรียกแบบนี้เลยก็ได้ ส่วนค่าตรง parameters ของ method จะแทนได้ทั้ง  get และ post เลยเช่นเดียวกัน แตกต่างกันตรงที่ parameter Zend Rest มีการจัดการ validate เรื่อง missing parameter ให้ด้วย เท่านั้นเอง

 

ทีนี้ผมจะลองเรียกไปใหม่ แบบนี้

http://xxx.com/api/rest/blogs?method=GetItem&id=123

ข้อความตอบกลับมาของผมก็คือ

 

นั่นก็เพราะผมยังไม่ได้ใส่ username + password ไปนั่นเอง เอาใหม่ทีนี้ใส่ให้ถูกๆ เป็น

http://xxx.com/api/rest/blogs?method=GetItem&id=123&username=Teepluss&password=123

ข้อความตอบกลับของผมก็จะเป็น

 

ถูกต้องตามปกติ และนอกจากนั้นแล้ว จากโคด ที่เราทำการเขียนไว้ต้องแต่ controller rest.php ยังสามารถทำให้เราจัดการกับ format ได้อีกด้วย เช่นผมพิมพ์ไปว่า

http://xxx.com/api/rest/blogs?method=GetItem&id=123&username=Teepluss&password=123&format=json

ค่าที่ตอบกลับมาผมจะได้มาใน format ของ  json ดังภาพด้านล่าง

 

ซึ่ง Format JSON นี่ล่ะ เหมาะนักในการไปใช้ใน โปรแกรมจาก อุปกรณ์ต่างๆ เช่น iPhone, Android เป็นต้น

 

ไม่ยากเกินไปใช่มั้ยครับ สำหรับ 4 เดือนที่หายไป วันนี้มีของมาฝากเท่านี้แหละ เห็นมั้ยล่ะ มันต้องพิมพ์เยอะแค่ไหน ในการอัพ บล็อกแต่ละที นี่ล่ะที่ขี้เกียจ T___T

เจอกันโอกาสหน้านะครับ

Tee++;

twitter stumbleupon delicious digg facebook

4 comments

Add comment Load previous All comments

Leave a comment

Post Comment

Powered by OSCOOL. You may view this on RSS or ATOM.

OSCOOL

  • Twitter
  • Facebook
  • Next