RESTful 리소스 처리
Representational State Transfer(REST)은 분산 애플리케이션을 위한 아키텍처 스타일로, Roy Fielding이 2000년 박사학위 논문 Architectural Styles and the Design of Network-based Software Architectures에서 처음 설명했습니다. 다소 딱딱한 내용일 수 있으니 Martin Fowler의 Richardson Maturity Model을 함께 읽어보면 더 친절한 소개가 될 것입니다.
REST는 다양한 방식으로 해석되거나 오해되어 왔습니다. 아키텍처에서 Roy Fielding의 원칙을 더 많이 수용할수록 애플리케이션은 더 “RESTful”하다고 볼 수 있습니다.
CodeIgniter는 리소스 라우트와 ResourceController를 통해 리소스용 RESTful API를 쉽게 만들 수 있도록 도와줍니다.
리소스 라우트
단일 리소스에 대해 resource() 메서드로 빠르게 여러 RESTful 라우트를 생성할 수 있습니다. 이는 리소스의 전체 CRUD에 필요한 다섯 가지 기본 라우트(생성, 수정, 목록 조회, 단일 항목 보기, 삭제)를 만듭니다. 첫 번째 매개변수는 리소스 이름입니다:
<?php
$routes->resource('photos');
// Equivalent to the following:
$routes->get('photos/new', 'Photos::new');
$routes->post('photos', 'Photos::create');
$routes->get('photos', 'Photos::index');
$routes->get('photos/(:segment)', 'Photos::show/$1');
$routes->get('photos/(:segment)/edit', 'Photos::edit/$1');
$routes->put('photos/(:segment)', 'Photos::update/$1');
$routes->patch('photos/(:segment)', 'Photos::update/$1');
$routes->delete('photos/(:segment)', 'Photos::delete/$1');
참고
위의 순서는 가독성을 위한 것이며, 실제로 RouteCollection에서 라우트가 생성되는 순서는 올바른 라우트 해석을 보장합니다.
중요
라우트는 지정된 순서대로 매칭되므로, 예를 들어 resource photos가 get ‘photos/poll’보다 위에 있으면 resource 라인의 show 액션 라우트가 get 라인보다 먼저 매칭됩니다. 이를 해결하려면 get 라인을 resource 라인 위로 이동시켜 먼저 매칭되도록 하세요.
두 번째 매개변수는 생성되는 라우트를 수정하는 옵션의 배열을 받습니다. 이 라우트들은 주로 API 용도로 사용되지만, websafe 옵션을 지정하면 HTML 폼과 함께 작동하는 update 및 delete 메서드를 생성할 수 있습니다:
<?php
$routes->resource('photos', ['websafe' => 1]);
// The following equivalent routes are created:
$routes->post('photos/(:segment)/delete', 'Photos::delete/$1');
$routes->post('photos/(:segment)', 'Photos::update/$1');
사용할 컨트롤러 변경
사용할 컨트롤러의 이름을 controller 옵션으로 지정할 수 있습니다:
<?php
$routes->resource('photos', ['controller' => 'Gallery']);
// Would create routes like:
$routes->get('photos', '\App\Controllers\Gallery::index');
<?php
$routes->resource('photos', ['controller' => '\App\Gallery']);
// Would create routes like:
$routes->get('photos', '\App\Gallery::index');
<?php
use App\Controllers\Gallery;
$routes->resource('photos', ['namespace' => '', 'controller' => Gallery::class]);
// Would create routes like:
$routes->get('photos', '\App\Controllers\Gallery::index');
또한 컨트롤러 네임스페이스을 참조하세요.
사용할 플레이스홀더 변경
기본적으로 리소스 ID가 필요할 때 (:segment) 플레이스홀더가 사용됩니다. placeholder 옵션에 새 문자열을 지정하여 변경할 수 있습니다:
<?php
$routes->resource('photos', ['placeholder' => '(:num)']);
// Generates routes like:
$routes->get('photos/(:num)', 'Photos::show/$1');
생성되는 라우트 제한
only 옵션으로 생성되는 라우트를 제한할 수 있습니다. 이 옵션은 생성할 메서드 이름의 배열 또는 쉼표로 구분된 목록이어야 하며, 해당 메서드와 일치하는 라우트만 생성됩니다. 나머지는 무시됩니다:
<?php
$routes->resource('photos', ['only' => ['index', 'show']]);
또는 except 옵션으로 사용하지 않는 라우트를 제거할 수 있습니다. 이 옵션 역시 메서드 이름의 배열 또는 쉼표로 구분된 목록이어야 하며, 이 옵션은 only 이후에 적용됩니다:
<?php
$routes->resource('photos', ['except' => 'new,edit']);
유효한 메서드는 index, show, create, update, new, edit 및 delete 입니다.
ResourceController
ResourceController는 위의 리소스 라우트에 대응하는 메서드를 제공하여 RESTful API를 시작하기 위한 편리한 기반을 제공합니다.
이를 확장하고 modelName 및 format 속성을 재정의한 다음, 처리할 메서드들을 구현하세요:
<?php
namespace App\Controllers;
use CodeIgniter\RESTful\ResourceController;
class Photos extends ResourceController
{
protected $modelName = 'App\Models\Photos';
protected $format = 'json';
public function index()
{
return $this->respond($this->model->findAll());
}
// ...
}
해당 라우팅은 다음과 같습니다:
<?php
$routes->resource('photos');
프레젠터 라우트
presenter() 메서드를 사용하여 리소스 컨트롤러와 일치하는 프레젠테이션 컨트롤러를 빠르게 생성할 수 있습니다. 이는 리소스의 뷰를 반환하거나 해당 뷰에서 제출된 폼을 처리하는 컨트롤러 메서드에 대한 라우트를 생성합니다.
프레젠테이션은 일반 컨트롤러로 처리할 수 있으므로 필수는 아니며 편의 기능입니다. 사용법은 리소스 라우팅과 유사합니다:
<?php
$routes->presenter('photos');
// Equivalent to the following:
$routes->get('photos/new', 'Photos::new');
$routes->post('photos/create', 'Photos::create');
$routes->post('photos', 'Photos::create'); // alias
$routes->get('photos', 'Photos::index');
$routes->get('photos/show/(:segment)', 'Photos::show/$1');
$routes->get('photos/(:segment)', 'Photos::show/$1'); // alias
$routes->get('photos/edit/(:segment)', 'Photos::edit/$1');
$routes->post('photos/update/(:segment)', 'Photos::update/$1');
$routes->get('photos/remove/(:segment)', 'Photos::remove/$1');
$routes->post('photos/delete/(:segment)', 'Photos::delete/$1');
참고
위의 순서는 가독성을 위한 것이며, 실제로 RouteCollection에서 라우트가 생성되는 순서는 올바른 라우트 해석을 보장합니다.
동일한 photos에 대해 리소스와 프레젠터 컨트롤러 둘 다 라우트를 가지지 않도록 구분해야 합니다. 예를 들어 다음과 같이 구별할 수 있습니다:
<?php
$routes->resource('api/photo');
$routes->presenter('admin/photos');
두 번째 매개변수는 생성되는 라우트를 수정하는 옵션 배열을 받습니다.
사용할 컨트롤러 변경
사용할 컨트롤러의 이름을 controller 옵션으로 지정할 수 있습니다:
<?php
$routes->presenter('photos', ['controller' => 'Gallery']);
// Would create routes like:
$routes->get('photos', '\App\Controllers\Gallery::index');
<?php
$routes->presenter('photos', ['controller' => '\App\Gallery']);
// Would create routes like:
$routes->get('photos', '\App\Gallery::index');
<?php
use App\Controllers\Gallery;
$routes->presenter('photos', ['namespace' => '', 'controller' => Gallery::class]);
// Would create routes like:
$routes->get('photos', '\App\Controllers\Gallery::index');
또한 컨트롤러 네임스페이스을 참조하세요.
사용할 플레이스홀더 변경
기본적으로 리소스 ID가 필요할 때 (:segment) 플레이스홀더가 사용됩니다. placeholder 옵션에 새 문자열을 지정하여 변경할 수 있습니다:
<?php
$routes->presenter('photos', ['placeholder' => '(:num)']);
// Generates routes like:
$routes->get('photos/(:num)', 'Photos::show/$1');
생성되는 라우트 제한
only 옵션으로 생성되는 라우트를 제한할 수 있습니다. 이 옵션은 생성할 메서드 이름의 배열 또는 쉼표로 구분된 목록이어야 하며, 해당 메서드와 일치하는 라우트만 생성됩니다. 나머지는 무시됩니다:
<?php
$routes->presenter('photos', ['only' => ['index', 'show']]);
또는 except 옵션으로 사용하지 않는 라우트를 제거할 수 있습니다. 이 옵션 역시 메서드 이름의 배열 또는 쉼표로 구분된 목록이어야 하며, 이 옵션은 only 이후에 적용됩니다:
<?php
$routes->presenter('photos', ['except' => 'new,edit']);
유효한 메서드는 index, show, new, create, edit, update, remove 및 delete 입니다.
ResourcePresenter
ResourcePresenter는 리소스의 뷰를 표시하고, 해당 뷰의 폼 데이터를 처리하기 위한 편리한 시작점을 제공하며, 위의 리소스 라우트와 일치하는 메서드를 제공합니다.
이를 확장하여 modelName 속성을 재정의하고, 처리하려는 메서드들을 구현하세요:
<?php
namespace App\Controllers;
use CodeIgniter\RESTful\ResourcePresenter;
class Photos extends ResourcePresenter
{
protected $modelName = 'App\Models\Photos';
public function index()
{
return view('templates/list', $this->model->findAll());
}
// ...
}
해당 라우팅은 다음과 같습니다:
<?php
$routes->presenter('photos');
프레젠터/컨트롤러 비교
이 표는 resource()와 presenter()가 생성하는 기본 라우트와 해당 컨트롤러 함수들을 비교하여 보여줍니다.
동작 |
메서드 |
컨트롤러 라우트 |
프레젠터 라우트 |
컨트롤러 함수 |
프레젠터 함수 |
|---|---|---|---|---|---|
새로 만들기 |
GET |
photos/new |
photos/new |
|
|
생성 |
POST |
photos |
photos |
|
|
생성(별칭) |
POST |
photos/create |
|
||
목록 |
GET |
photos |
photos |
|
|
보기 |
GET |
photos/(:segment) |
photos/(:segment) |
|
|
보기(별칭) |
GET |
photos/show/(:segment) |
|
||
편집 |
GET |
photos/(:segment)/edit |
photos/edit/(:segment) |
|
|
업데이트 |
PUT/PATCH |
photos/(:segment) |
|
||
업데이트(웹세이프) |
POST |
photos/(:segment) |
photos/update/(:segment) |
|
|
제거 |
GET |
photos/remove/(:segment) |
|
||
삭제 |
DELETE |
photos/(:segment) |
|
||
삭제(웹세이프) |
POST |
photos/delete/(:segment) |
|
|