웹 개발을 진행하다 보면 프론트엔드와 백엔드 간의 데이터 통신을 효율적으로 처리하기 위해 다양한 라이브러리와 쿼리 언어를 결합하게 됩니다. 이번 글에서는 강력한 UI 프레임워크인 Kendo UI for jQuery와 유연한 데이터 쿼리를 제공하는 GraphQL 서비스 기술을 서로 바인딩하여 데이터를 조회하고 처리하는 방법에 대해 자세히 알아봅니다.
📌 목차
- 1. Kendo UI와 GraphQL 연동 개요
- 2. 프론트엔드: Kendo UI DataSource 및 GraphQL 쿼리 설정
- 3. 백엔드 라우팅 및 JSON 처리 구조
- 4. GraphQL 데이터 제어를 위한 PHP 함수 구현
1. Kendo UI와 GraphQL 연동 개요
Kendo UI for jQuery는 다양한 엔터프라이즈급 UI 컴포넌트를 제공하는 라이브러리입니다. 특히 DataSource 컴포넌트는 원격 데이터 소스와 손쉽게 연동할 수 있는 강력한 인터페이스를 제공합니다.
여기에 최신 데이터 통신 규격인 GraphQL을 결합하면 클라이언트가 필요한 데이터 구조를 명시적으로 요청하고 처리할 수 있어, RESTful API 방식보다 더욱 유연하고 확장성 있는 CRUD 애플리케이션을 구축할 수 있습니다.
2. 프론트엔드: Kendo UI DataSource 및 GraphQL 쿼리 설정
프론트엔드 영역에서는 데이터를 조회하기 위한 SA_READ_QUERY와 생성, 수정, 삭제를 담당하는 뮤테이션 쿼리(SA_ADD_QUERY, SA_UPDATE_QUERY, SA_DELETE_QUERY)를 정의합니다.
DataSource의 transport 설정 내에서 각 작업별 엔드포인트와 parameterMap을 구성하여 쿼리와 변수 데이터를 서버로 전송합니다.
let SA_READ_QUERY = "query {" +
"products { id, tcode, bcode, bsort, boname }" +
"}";
let SA_ADD_QUERY = "mutation CreateProductMutation($product: ProductInput!){" +
"createProduct(product: $product){" +
"id,"+
"tcode,"+
"bcode,"+
"bsort,"+
"boname"+
"}"+
"}";
let SA_UPDATE_QUERY = "mutation UpdateProductMutation($product: ProductInput!){" +
"updateProduct(product: $product){" +
"id,"+
"tcode,"+
"bcode,"+
"bsort,"+
"boname"+
"}" +
"}";
let SA_DELETE_QUERY = "mutation DeleteProductMutation($product: ProductInput!){" +
"deleteProduct(product: $product){" +
"id,"+
"tcode,"+
"bcode,"+
"bsort,"+
"boname"+
"}"+
"}";
$(document).ready(function() {
let dataSource = new kendo.data.DataSource({
transport: {
create: {
contentType: "application/json",
url: "/json/!/module/add_board_manage",
type: "POST",
data: function(model) {
return {
query: SA_ADD_QUERY,
variables: {"product": model}
};
}
},
read: {
contentType: "application/json",
url: "/json/!/module/get_board_manage",
type: "POST",
dataType: "json",
data: function(model){
return {
query: SA_READ_QUERY,
variables: {"product": model}
}
}
},
update: {
contentType: "application/json",
url: "/json/!/module/update_board_manage",
type: "POST",
dataType: "json",
data: function(model) {
return {
query: SA_UPDATE_QUERY,
variables: {"product": model}
};
}
},
destroy: {
contentType: "application/json",
url: "/json/!/module/delete_board_manage",
type: "POST",
data: function(model) {
return {
query: SA_DELETE_QUERY,
variables: {"product": model}
};
}
},
parameterMap: function(options, operation) {
return kendo.stringify({
query: options.query,
variables: options.variables
});
}
},
schema: {
data: function(response) {
var data = response.data;
if (data.products) { return data.products; }
else if (data.createProduct) { return data.createProduct; }
else if (data.updateProduct) { return data.updateProduct; }
else if (data.deleteProduct) { return data.deleteProduct; }
},
total: function(response) {
return response.data.products.length;
},
model: {
id: "id",
fields: {
id: { type: "number", editable: false },
tcode: { type: "string" },
bcode: { type: "string" },
bsort: { type: "number" },
boname: { type: "string" }
}
}
},
pageSize: 20
});
$("#grid").kendoGrid({
dataSource: dataSource,
height: 650,
groupable: false
});
});
3. 백엔드 라우팅 및 JSON 처리 구조
서버 측 진입점인 json.php 파일에서는 요청된 $module 값을 분석하여 action, mod, target 변수로 분할합니다.
분할된 정보에 맞춰 필요한 공통 라이브러리 및 모듈 파일을 동적으로 로드한 뒤, 후속 사용자 요청 데이터($_REQUEST)와 함께 콜백 함수를 호출하여 처리 결과를 반환합니다.
<?php require'./sa_common.php';
require declare_loader('lib/json_lib', __FILE__);
if ($module = $request->segment()['module'])
{
list($action, $mod, $target) = explode('_', $module);
}
if (has_equals($mod, 'board'))
{
require_once declare_loader('forum/_common', __FILE__);
}
if ($target) {
$module = str_replace('_'.$target,'',$module);
}
return call_user_func('json_'.$module, $target, $param = $_REQUEST);
?>
4. GraphQL 데이터 제어를 위한 PHP 함수 구현
핵심 비즈니스 로직을 처리하는 json_lib.php 라이브러리에서는 게시판 생성, 추가, 수정, 삭제 및 조회 기능을 각각의 함수로 구현합니다.
요청된 $target 파라미터와 전달받은 $param 데이터를 기반으로 모델 객체를 제어하고, 최종 결과를 json_encode()를 통해 클라이언트에 전달합니다.
<?php function json() {
return true;
}
function json_empty($target = 'products')
{
return array(
'data'=> array(
$target=> []
)
);
}
function json_create_board($target, $param = null)
{
if (!$target) return;
if ($target == 'manage') {
if ($tcode = $param['tcode']) {
BoardManage::createBoard($tcode);
}
}
return json_list_board($target);
}
function json_add_board($target, $param = null)
{
if (!$target) return;
if ($target == 'manage') {
if ($param['tcode'] && $param['boname']) {
$manage = new BoardManage;
$manage->load();
}
}
return json_list_board($target);
}
function json_update_board($target, $param = null)
{
if (!$target || !$param['id']) return;
if ($target == 'manage') {
$manage = new BoardManage;
$manage->id = $param['id'];
$manage->load();
$manage->boname = $param['boname'];
$manage->manageBonameModify();
}
return json_list_board($target);
}
function json_delete_board($target, $param = null)
{
if (!$target || !$param['id']) return;
if ($target == 'manage') {
$manage = new BoardManage;
$manage->id = $param['id'];
$manage->load();
$manage->deleteBoard();
}
return json_list_board($target);
}
function json_get_board($target, $param = null)
{
if (!$target) return;
if ($param['id']) {
return json_read_board($target, $param);
}
return json_list_board($target, $param);
}
function json_read_board($target, $param = null)
{
if (!$target || !$param['id']) return;
$response = json_empty();
if ($target == 'manage') {
$manage = new BoardManage;
$manage->id = $param['id'];
$manage->delyn = 'N';
$response['data']['products'][] = $manage->load();
}
echo json_encode($response);
}
function json_list_board($target, $param = null)
{
if (!$target) return;
$response = json_empty();
if ($target == 'manage') {
$response['data']['products'] = BoardManage::retrieve(array(
'delyn' => 'N',
));
}
echo json_encode($response);
}
?>