다음 PHP/MySQL 프로젝트는 최근에 수행한 MySQL 데이터베이스 설정, HTML이 포함된 PHP 뷰 작성, 필요에 따라 Javascript 코드와 CSS 파일 추가, 데이터베이스에 연결, 데이터베이스에서 컨텐츠를 추출하여 해당 뷰에 채우기 등과 같은 여러 가지 프로젝트와 비슷하다. 웹 개발에 익숙하다면 기능 코드를 분리하는 데 따른 이점을 알고 있을 것이다. 예를 들면, 원시 SQL 쿼리를 직접 뷰에 입력하지 않아도 되는 방법을 알고 있을 것이며 데이터베이스에서 데이터를 추출하는 함수나 클래스의 내부에 HTML 태그를 무질서하게 삽입하지는 않을 것이다.
그러나 언젠가는 프로젝트가 정상적인 PHP/MySQL에서 처리할 수 있는 수준 이상으로 확장될 수 있다. 예를 들면, 데이터베이스의 데이터를 필요로 하는 보통의 웹 뷰뿐만 아니라 이러한 데이터를 액세스하는 모바일 장치(스마트폰) 및 Facebook과 같은 외부 애플리케이션이 필요할 수도 있다.
데이터베이스가 변경되거나 일종의 플랫 파일 XML 저장소를 처리해야 하는 상황에 있을 수도 있다. 이러한 상황에서는 MySQL을 맹목적으로 신뢰하는 것이 프로젝트를 완성하는 데 방해가 될 수 있다.
RESTful JSON 제어기를 프로젝트에 삽입하여 이 제어기를 데이터 소스에 요청을 전송하여 응답을 받는 가상의 "트래픽 감시자"로 사용해 보자. 이 기사에서는 REST와 JSON의 기본적인 내용과 JSON 제어기를 설정하는 하나의 방법을 살펴본다. 이렇게 함으로써 PHP나 Javascript 코드로 쉽게 구문 분석할 수 있는 표준 형식의 소스에서 데이터를 쉽게 검색할 수 있다.
일반적인 REST 아키텍처에서는 클라이언트가 서버에 요청을 하면 서버는 이에 대한 응답으로 요청 받은 자원을 표시한다. 자원은 데이터베이스나 문서와 같은 거의 모든 정보 오브젝트가 될 수 있으며 이러한 오브젝트는 오브젝트의 현재 상태나 요청된 상태의 스냅샷 역할을 하는 형식화된 문서(XML이나 JSON)로 표시된다.
REST 자원은 일반적으로 GET, POST, PUT 및 DELETE와 같은 다양한 요청 "명령어"를 받는 의미있는 URL을 사용하여 식별된다. 이러한 명령어는
많은 개발자들에게 익숙한 CRUD(Create-Retrieve-Update-Delete) 모델과 다소 유사하다.
예를 들면, 데이터를 검색할 경우에는 GET 요청을 사용하고 데이터를 작성할 경우에는 POST 요청을 사용하며, 데이터를 업데이트할 경우에는
PUT 요청을 사용하고 데이터를 삭제할 경우에는 DELETE 요청을 사용한다.
고려해야 할 또 다른 중요한 요소는 응답이다. RESTful 서비스는 일반적으로 응답 과정에서 두 가지 의미있는 컴포넌트(응답 본문 자체와 상태 코드)를
제공한다. 실제로 대부분의 REST 서버에서는 사용자가 ACCEPT 매개변수로 전송하거나 파일 확장자(예: /api/users.xml이나 /api/users.json)를 지정하여
직렬화된 PHP나 XML, CSV, 일반 텍스트와 같은 응답 형식을 지정할 수 있다. 이 기사에서 구현하게 될 다른 REST 서버에서는 하드 코드된 응답 형식을
사용한다. 이러한 응답 형식도 문서화되어 있기만 하면 똑같이 사용할 수 있다.
응답 코드는 HTTP 상태 코드가 된다. 이 스키마의 장점은 사용자가 기존의 잘 알려진 상태 코드를 사용하여 오류나 성공을 식별할 수 있다는
점이다. POST 요청이 성공적으로 수행되면 201 상태 코드(CREATED)가 전송된다.
500 오류 코드는 서버측에서의 실패를 나타내지만 400 오류 코드는 클라이언트 측에서의 실패(BAD REQUEST)를 나타낸다. 서버에서 어떤 오류가 발생하면
503(SERVICE UNAVAILABLE) 오류 코드가 전송된다.
성, 이름, 이메일 주소 및 Twitter 계정과 같은 사용자 정보가 포함된 데이터 소스를 사용하는 애플리케이션을 생각해 보자. 일반적인 PHP 애플리케이션을
설정하는 경우에는 mysql_query() 랩퍼를 작성하고 SQL 쿼리를 사용하여 데이터베이스에서 목록을 추출한다. 또한, 이 함수를 호출하고 루프를 통해 결과 세트를
처리하여 애플리케이션 뷰에 데이터를 표시할 PHP 코드들 일부 작성한다.
더욱 간단한 방법은 다른 매개변수를 사용하지 않고도 /users/list에 GET 요청을 할 수 있고 해당 데이터베이스 함수를 차례로 호출하여 JSON 형식으로 목록을
리턴하는 간단한 REST 제어기를 설정하는 것이다. 그러면 애플리케이션에서 JSON 데이터를 디코드하고 어떤 식으로라도 이 데이터를 루프를 통해 처리하여 해당 내용을 표시한다.
또한, /users/list에 매개변수가 전송되었는지 테스트를 통해 확인할 수 있다. 예를 들어, /users/list/1에 GET 요청을 전송하면 응답에는 ID가 1인 사용자의
세부정보만 포함된다. 직렬화된 PHP나 XML, CSV와 같은 형식을 허용하는 것도 가능하다.
RESTful JSON 제어기는 뷰와 데이터 소스 사이에 특별한 기능 계층을 추가하기보다는 개발에 들어가는 노력을 줄이는 데 도움을 준다. 기본적인 PHP 뷰 외에도 다양한 곳에서 정보를 요청할 수 있다고 생각해 보자. 예를 들면, 개발자라면 jQuery를 사용하여 Ajax 인터페이스를 통해 정보를 요청할 수 있으며 사용자라면 스마트폰이나 Facebook 애플리케이션을 통해 정보를 요청할 수 있다.
이러한 경우에 요청을 받아서 인식하고 예측하기 쉬운 형식으로 응답하는 RESTful 인터페이스를 이용하면 개발에 들어가는 노력을 대폭 줄일 수 있다. PHP 뷰나 iPhone 애플리케이션을 담당하는 개발자는 URL에 요청을 전송하여 예상 응답 세트를 수신할 수 있다. JSON 제어기의 단점은 애플리케이션이 MySQL, PostgreSQL, XML 파일 저장소에 종속될 가능성이 있다는 점이다.
JSON은 컴퓨터와 인간이 모두 쉽게 이해하고 사용할 수 있는 텍스트 기반의 경량 데이터 교환 형식이다. 처음에 JSON은 간단한 데이터 구조를 표현하도록
설계되었다. 원래 JSON은 특별히 Javascript에 친화적인 데이터를 전송하는 방식으로 여겨졌지만, 현재는 사실상 모든 컴퓨터 언어에서 JSON 구문 분석기를
사용할 수 있다. PHP에서는 한 쌍의 원시 JSON 함수(json_encode 및 json_decode)를 이용하여 다수의 복잡한 작업을 처리할 수 있다. 데이터 배열이나
간단한 문자열로 json_encode에 간단히 전송하면 JSON 오브젝트는 Listing 1과 같이 표시된다.
Listing 1. PHP 배열 대 JSON 오브젝트
$data = array(
'firstname' => 'Tom',
'lastname' => 'Smith',
'age' => 40
);
print_r($data);
/* prints
Array(
[firstname] => Tom
[lastname] => Smith
[age] => 40
)
*/
echo json_encode($data);
/* prints
{ "firstname": "Tom",
"lastname": "Smith",
"age":40
}
*/
|
SQL 쿼리의 결과로 생성되는 일반적인 PHP 배열(여기서 키와 값은 각각 데이터베이스 필드 이름과 데이터에 해당)은 JSON 오브젝트로
쉽게 전송된다. 데이터가 도착하면 Javascript 코드에서 eval() 함수를 사용하여 데이터를 간단히 처리하거나 PHP에서 json_decode() 함수로 디코드하여
다시 데이터 배열로 만들 수 있다.
JSON 데이터는 오브젝트 외에도 문자열, 널값, 숫자(정수나 실수), 부울값 및 배열(연속된 값을 쉼표로 분리하고 대괄호로 둘러싼 것)과 같은 다양한 데이터 유형을 지원한다. 결과적으로 JSON을 사용하면 데이터를 유연하게 처리할 수 있다.
이 기사를 통해 모델과 뷰 기능 사이에 배치할 수 있는 간단한 JSON REST 제어기를 빌드할 수 있다. JSON 제어기를 빌드한 후에는 프로젝트의 목적에 맞춰 자체적으로 확장 규모를 조정할 수 있다.
이벤트 정보를 제공하는 애플리케이션을 생각하자. 모든 이벤트 정보는 공용이며 따라서 여기에서는 인증 문제가 중요하지 않다. 게다가 목적은 현재 일어나고 있는 이벤트를 쿼리하고 JSON을 사용하여 요청 발신자에게 다시 응답을 전송하는 데 있다. 지금은 요청자가 PHP 뷰 페이지라고 가정한다.
먼저, 이벤트를 처리하기 위해 Listing 2에 있는 스키마와 같은 간단한 데이터베이스 스키마를 작성한다.
Listing 2. 데이터베이스 스키마(MySQL)
CREATE TABLE `events` ( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , `title` VARCHAR( 255 ) NOT NULL , `address` VARCHAR( 255 ) NOT NULL , `start_time` DATETIME NOT NULL , `description` TEXT NOT NULL ); |
데이터베이스 테이블을 작성한 후에는 몇 개의 모의 데이터 레코드를 입력한다. 적어도 1일에 여러 개의 항목이 스케줄되어 있는지 확인한다.
그런 다음, 이 데이터베이스에 연결하고 SQL 쿼리를 사용하여 이벤트를 식별할 일반적인 PHP 모델 파일을 작성한다. 실제 애플리케이션에서는 데이터베이스 연결 스크립트를 나머지 스크립트와 분리하고 모든 종류의 데이터 유효성을 쿼리 내에서 확인한다. 코드는 Listing 3과 같이 된다.
Listing 3. 간단한 쿼리
$SERVER = 'name';
$USER = 'username';
$PASS = 'pw';
$DATABASE = 'dbname';
if (!($mylink = mysql_connect( $SERVER, $USER, $PASS)))
{
echo "Sorry, could not connect to DB. Contact your sysadmin for help!";
exit;
}
mysql_select_db( $DATABASE );
class Events{
function get_events($day){
$ret_array = array();
$sql = "select id,title,address,start_time,description
from events where start_time like '$day%'
order by start_time asc";
$result = mysql_query($sql);
while($data = mysql_fetch_object($result)){
$obj['id'] = $data->id;
$obj['title'] = $data->title;
$obj['address'] = $data->address;
$obj['start_time'] = $data->start_time;
$obj['description'] = $data->description;
$ret_array[] = $obj;
}
return $ret_array;
}
}
|
특정 날짜에서 이 함수를 간단히 호출하면 일부 이벤트가 검색되며 검색 결과는 Listing 4와 같다.
Listing 4. 쿼리를 실행한 결과
$EVENT = new Events; $today = '2010-06-17'; $events = $EVENT->get_events($today); print_r($events); /* results in Array ( [0] => Array ( [id] => 2 [title] => Event #2 [address] => 156 My Avenue, MyTown, USA 78727 [start_time] => 2010-06-17 11:30:00 [description] => Join us for lunch to hear FABULOUS SPEAKER. ) [1] => Array ( [id] => 1 [title] => Event #1 [address] => 123 My Street, Anytown USA 78727 [start_time] => 2010-06-17 15:30:00 [description] => A great event! Hope to see you there! ) ) */ |
같은 코드를 json_encode() 함수를 통해 실행하면 Listing 5와 같은 이식 가능한 JSON 오브젝트를 얻게 된다.
Listing 5. JSON 데이터 오브젝트
[
{"id":"2",
"title":"Event #2",
"address":"156 My Avenue, MyTown, USA 78727",
"start_time":"2010-06-17 11:30:00",
"description":"Join us for lunch to hear FABULOUS SPEAKER. "
},
{"id":"1",
"title":"Event #1",
"address":"123 My Street, Anytown USA 78727",
"start_time":"2010-06-17 15:30:00",
"description":"A great event! Hope to see you there!"
}
]
|
목표는 어떤 모델과 함수를 실행할 것인지 인식하여 트랜잭션의 마지막 부분에서 쓰기에 편리한 JSON 오브젝트를 응답으로 리턴하는 간단한 제어기를 빌드하는 데 있다. 이 제어기는 매우 간단하며 Listing 6과 같은 형태가 된다. 이 코드를 모두 json.php 파일에 붙여 넣는다.
Listing 6. 간단한 제어기
class JSON{
var $response = '';
function JSON($model,$function,$params){
$REQUEST = new $model;
$data = $REQUEST->$function($params);
$this->response = json_encode($data);
}
}
|
이 코드를 작동하게 하려면 호출할 모델이 필요하며 JSON 클래스를 인스턴스화한 다음,
세 개의 매개변수(모델의 클래스 이름, 실행할 함수 및 이 함수를 위한 매개변수)로 전달한다.
그러면 이 클래스가 해당 함수를 호출하여 json_encode() 함수를 통해 실행할 응답을 얻는다.
마지막 단계에서는 JSON 데이터를 처리하기 위한 요청이 포함된 파일을 작성한다. listing.php를 호출할 수 있는 이 특별한 파일은
세 개의 GET 변수(모델, 함수 및 매개변수에 대해서 각 하나씩)를 수락하도록 설정할 수 있으며, 그런 다음 이 변수를 Listing 7에 있는 것과 같은 JSON 클래스에
전달한다.
Listing 7. 요청 코드
//this is the code that contains the model
require 'events.php';
//this is the JSON controller
require 'json.php';
//pass in your three GET parameters
$MODEL = $_GET['model'];
$FUNCTION = $_GET['function'];
//check to see if param is passed in
//if not, use today's date in this instance
if (isset($_GET['param'])){
$PARAM = $_GET['param'];
}else{
$PARAM = date("Y-m-d");
}
//invoke
$JSON = new JSON($MODEL,$FUNCTION,$PARAM);
//access the response variable
echo $JSON->response;
|
이 시점에서 이 파일을 브라우저로 로드하면 Listing 5에 있는 것과 비슷한 JSON 오브젝트를 얻을 수 있다. json_decode() 함수를 통해
JSON 오브젝트를 전송하고 Javascript 코드를 사용하여 처리하거나 그대로 남겨둘 수 있다.
이러한 전체 프로세스를 훨씬 더 나은 방법으로 처리하려면 RESTful 서버를 더욱 충실하게 에뮬레이트하는 경로 구조를 작성해야 한다. 예를 들면, events/today와 같은 디렉토리 구조를 작성하여 index.php 파일을 수용할 수 있다. 브라우저에서 /event/today를 가리키면 GET 변수를 전달하지 않고도
Listing 8에 있는 코드를 기반으로 JSON 피드를 다시 얻을 수 있다.
Listing 8. /events/today/index.php의 코드
require '../../events.php';
require '../../json.php';
$MODEL = "Events";
$FUNCTION = "get_events";
$PARAM = date("Y-m-d");
//invoke
$JSON = new JSON($MODEL,$FUNCTION,$PARAM);
echo $JSON->response;
//prints out
[
{"id":"3",
"title":"Test Event 3",
"address":"111 Main Street, Austin TX 78727",
"start_time":"2010-06-10 15:15:00",
"description":"Testing 456."
}
]
|
이 방식을 사용하면 지원 애플리케이션과 뷰의 데이터 추출 요구사항 중 일부를 단순화할 수 있다. 기본 데이터베이스의 모든 세부사항을 기억해야 하는 대신 개발자는 URL을 쉽게 떠올려서 원하는 응답을 수신하고 자신의 작업을 계속 추진할 수 있다.
교육
- JSON에 관해 자세히 배울 수 있다.
- PHP 사이트에서 JSON 문서에 관한 자세한 정보를 읽어보자.
- developerWorks 웹 개발 사이트에서는 다양한 웹 기반
솔루션을 다루는 기사를 전문적으로 게시한다.
- developerWorks의 기술 행사 및 웹 캐스트를 통해 최신 정보를 얻을 수 있다.
- developerWorks on-demand demos에서는 입문자를 위한 제품 설치 및 설정부터 숙련된 개발자를 위한 고급 기능에 이르기까지 다양한 데모를 제공한다.
제품 및 기술 얻기
-
IBM 제품 평가판을 다운로드하거나 IBM SOA Sandbox의 온라인 시험판을 살펴보고 DB2®, Lotus®, Rational®,
Tivoli® 및 WebSphere의 애플리케이션 개발 도구와 미들웨어 제품을 사용해 볼 수 있다.
토론
- 지금 My developerWorks 프로파일을 작성하고 JSON에 대한 관심 목록을 설정해 보자. My developerWorks에 연결하여 늘 최신 정보를 확인한다.
- 웹
개발에 관심이 있는 다른 developerWorks 구성원을 찾아보자.
- My developerWorks:
그룹에서 웹 개발자들과 서로의 웹 개발 경험과 지식을 공유할 수 있다.
- 지식 공유: 웹 주제를
중점적으로 다루는 developerWorks 그룹 중 하나에 참여하자.
- Roland Barcia는 자신의 블로그에서
Web 2.0 및 미들웨어에 대해 설명했다.
- developerWorks 멤버의 shared
bookmarks on web topics를 따라가 보자.
- 빠른 해답: Web 2.0 Apps forum을 방문한다.
Thomas Myer is the cofounder of Triple Dog Dare Media, an Austin, Texas, consulting firm. Thomas writes on the subjects of knowledge management, information design, and usability. You can email him at tom@tripledogdaremedia.com.