Что такое REST, RESTFul и CRUD
22-05-2020Время чтения ~ 4 мин.PHP 20323
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 примерно так, как он изначально и задумывался.
Понравилось пояснение. Хотя бы перестал пугаться (или путать, если угодно) аббревиатуру с приставкой Ful. Спасибо.