Сайт вебмастера

Что такое REST, RESTFul и CRUD

22-05-2020Время чтения ~ 4 мин.PHP 20103

REST — это концепция для взаимодействия компонентов основанный на протоколе HTTP. Не хочу останавливаться на скучной теории (вики в помощь), а дам простое объяснение применительно к сайтам.

В Сети обмен происходит по протоколу HTTP: запрос - ответ. Для того, чтобы передать какие-то данные, их нужно как-то идентифицировать, то есть указать их «признак», «действие» или что-то подобное. И поэтому раньше данные требовалось оформить в виде какого-то сложного формата, обычно это XML или Json.

Так вот, REST говорит что этого делать не нужно. Данные передаём как есть, только у HTTP-запроса указывается метод (параметр) для этих данных. Обычно мы оперируем GET и POST, поскольку они работают «из коробки» в HTML и их поддерживает любой браузер. Но на самом деле, метод у HTTP может быть абсолютно любым. Есть некие общепринятые: PUT, DELETE, OPTIONS, PATCH, но это совсем не стандарт.

То есть, например мы хотим отправить на сервер GET-запрос по адресу сайт/task и получить список задач (таски). Потом мы хотим добавить новую задачу: отправляем на тот же адрес сайт/task, но уже методом POST. Потом решили, что для редактирования задачи нужно отправить уже PUT и опять же на тот же адрес. И, уж коли пошла такая пьянка, то отправляем и метод DELETE для удаления какой-то задачи.

Формирование GET-запроса очень простое — достаточно набрать адрес в браузере. Для POST уже нужна html-форма с method=post. Эти же методы прекрасно работают и через AJAX. Но, что касается PUT и DELETE, то ни HTML, ни браузер о них ничего не знают. Формально мы всё-таки можем их указывать, но наткнёмся на последнюю стенку — сервер, который также как правило ничего не знает об этих методах и рубанётся с ошибкой 501 или 405.

Таким образом, хоть HTTP и поддерживает произвольные методы, но в реальности работают только два: GET и POST.

Чтобы обойти это ограничение и применить REST к нашим сайтам, придумали хитрость. Все «нестандартные» запросы в своём теле должны содержать отдельное поле, где и указывается «желаемый» метод.

Устоявшаяся практика — метод указывать в поле _method формы или Ajax-запроса.

<form method="POST">
	<input type="hidden" name="_method" value="PUT">
	... прочие данные формы ...
</form>

То есть реальная отправка это POST, но приложение проверяет поле _method и по нему уже принимает решение что делать дальше.

Такой разбор выполняет роутер приложения. Если это так, то правила роутинга указываются примерно так:

[
    'method' => 'POST', // create new task (Create)
    'pattern' => 'task',
    'action' => '\Controller\Task\Task@create',
],
[
    'method' => 'GET', // task show (Read)
    'pattern' => 'task',
    'action' => '\Controller\Task\Task@read',
],
[
    'method' => 'PUT', // update/edit task (Update)
    'pattern' => 'task',
    'action' => '\Controller\Task\Task@update',
],
[
    'method' => 'DELETE', // delete task (Delete)
    'pattern' => 'task',
    'action' => '\Controller\Task\Task@delete',
]

Обратите внимание, что во всех случаях используется один http-адрес: сайт/task — меняются только методы, которые указываются либо в html-форме, либо Ajax-запросе.

Здесь мы подходим к другой концепции - CRUD, которая не что иное, как аббревиатура от Create, Read, Update, Delete — Создать, Прочитать, Обновить, Удалить. Это не что иное, как основные операции для подавляющего большинства данных.

CRUD нужен для того, чтобы разделить программный код на отдельные части, каждая из которых отвечает за свои действия. В данном примере будет использован php-класс \Controller\Task\Task, где каждый http-метод будет выполнен своим php-методом:

  • для POST будет выполнен метод create()
  • для GET будет выполнен метод read()
  • для PUT будет выполнен метод update()
  • для DELETE будет выполнен метод delete()

Если не использовать REST, то скорее всего пришлось бы указывать действие либо по отдельному url-адресу, либо в get-параметрах. Как-то так:

  • сайт/task/create
  • сайт/task/update/7
  • сайт/task/delete/5
  • сайт/task?action=create
  • сайт/task?action=update&id=7
  • сайт/task?action=delete&id=5

Для REST, конечно, требуется хоть какой-то роутинг, способный понимать _method. В общем случае это будет так:

$method = 'get'; // метод по умолчанию
 
if ($_POST) {
    if (isset($_POST['_method'])) 
        $method = $_POST['_method'];
    else 
        $method = 'post';
}
...

Дальше роутер смотрит правила и находит php-метод для запуска.

REST — это только концепция, набор правил. Если же применять эти правила к приложению, то уже говорят о RESTFul. Например REST предполагает использование модели «клиент-сервер». Если мы предположим, что сервер — это реальный сервер хостинга, а клиент — пользователь сайта, то для RESTFul нужно уже настраивать реальный сервер, чтобы он понимал используемые http-методы. Вряд ли кто-то будет это делать, поэтому с этой точки зрения приложение не может считаться RESTFul.

Но, с другой стороны, если REST-сервер — это просто абстракция, то какая нам разница как вообще работает реальный сервер, если его основная задача — просто отдавать и принимать что нам нужно? Даже если мы используем хитрость с _method, это работает как положено, а значит приложение соответствует RESTFul.

В целом стоит отметить, что сейчас REST и RESTFul — фактически синонимы. Если php-приложение может принимать хоть каким-то способом http-метод, то считается, что это уже полноценный RESTFul. Нужно просто понимать, что архитектура REST позволяет нам использовать HTTP примерно так, как он изначально и задумывался.

Похожие записи
Комментарии (1) RSS
1 Виктор 2020-05-26 14:13:45
REST — это только концепция, набор правил. Если же применять эти правила к приложению, то уже говорят о RESTFul

Понравилось пояснение. Хотя бы перестал пугаться (или путать, если угодно) аббревиатуру с приставкой Ful. Спасибо.