Взгляд на REST архитектуру со стороны сервера (PHP версия)
Вступление
В предыдущей статье я немного рассказал о REST архитектуре, её основных принципах, особенностях со стороны клиента и взгляде со стороны пользователя. Не смотря на то, что данный подход не новый, особой популярностью он стал пользоваться относительно недавно (не путать с ЧПУ (человеко-понятными урлами)). Как уже говорилось ранее, REST это не какая-то конкретная реализация, а совокупность некоторых принципов, которые учитываются при разработке.
Основная идея REST - это работа с ресурсами приложения как с отдельно взятыми объектами.
Принципы при разработке:
- URL адреса как уникальные пути к объектам (site.ru/caterogy/1)
- Действия над объектами определяет тип запроса (GET, POST, PUT, DELETE)
- Использование кодов ответов от сервера (список кодов с википедии)
Из [gml.link/users/1] в [index.php?source=users&id=1]
Для преобразования запросов, нам понадобится модуль RewriteEngine сервера Apache. Включение и конфигурация происходит в файле .htaccess (не знаю тонкостей настройки, но ниже написанные выражения исправно работают)
- RewriteEngine On
- RewriteBase /gml
- RewriteRule ^index.php$ / [QSA,L]
- RewriteRule ^([a-z]*)$ index.php?source=$1 [QSA,L]
- RewriteRule ^([a-z]*)/([0-9]*)$ index.php?source=$1&id=$2 [QSA,L]
Данная конфигурация включает RewriteEngine и задает некоторые правила для замены. Напомню, что это актуально только для Apache серверов. На NGINX серверах другая магия (ngx_http_rewrite_module).
Взгляд изнутри
Вернемся к нашей архитектуре и рассмотрим как подготовить бекэнд. Для начала вспомним идеологию REST: "URL адреса как пути к объектам (site.ru/caterogy/1)" и "Действия над объектами определяет тип запроса (GET, POST, PUT, DELETE)". Из этого следует что нам нужно знать адрес запроса, тип запроса и соответственно данные, которые передает запрос. Для получения этой информации, я написал небольшой класс роутинга: (я не мастер нейминга переменных, поэтому не судите строго)
Напомню что запрос приходит в виде index.php?source=users&id=1
- class RequestInfo {
- public $method;
- public $query=[];
- public $request=[];
- public $ajax;
- public function __construct($server) {
- //получаем метод запроса (PUT, GET, POST, DELETE)
- $this->method=$server['REQUEST_METHOD'];
- //если запрос ajax то true, иначе false
- $this->ajax=($server['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') ? true : false;
- //вытаскиваем данные из запроса
- $this->request=$this->get_request();
- //парсим стороку запроса (то что идет после index.php?) в ассоциативный массив
- parse_str($server['QUERY_STRING'], $this->query);
- }
- //вытаскиваем данные из запроса
- private function get_request() {
- $request=false;
- //небольшой хинт, если запрос PUT то данные получаем из php://input
- if ($this->method=='PUT') parse_str(file_get_contents('php://input'), $request);
- else if ($this->method=='POST') $request=$_POST;
- return $request;
- }
- }
- //создаем наш объект и передаем ему переменную $_SERVER в которой содержится вся информация о запросе
- $RInfo=new RequestInfo($_SERVER);
- //передаем обработанные данные запроса нашему контроллеру
- $app=new App($RInfo);
--------------------------------------------------
Пример запроса регистрации нового пользователя:
POST gml.link/users (gml.link/index.php?source=users), {email: 'alex@mail.ru', username: 'George', password: 'c69572f946edd2560d6c97eee2172d90'}
В итоге получаем следующий объект:
- object(RequestInfo)
- 'method' =>'POST'
- 'query' =>
- 'source' =>'users'
- 'id' =>''
- 'request' =>
- 'email' =>'alex@mail.ru'
- 'username' =>'George'
- 'password' =>'c69572f946edd2560d6c97eee2172d90'
- 'ajax' =>true
(выглядит код конечно странно, но тут нет нормального форматирования)
Имея всю необходимую информацию, мы передаем полученные данные из запроса в главный контроллер нашего приложения, который уже определяет дальнейшие действия и вызывает нужный обработчик. Так же не забываем для ответа выставлять правильные заголовки с кодами (ссылка на коды вначале статьи), а не только OK 200.
Заключение
Вот таким нехитрым способом устроена архитектура REST на сервере. Конечно реализации могут отличаться, но суть одна: нужно знать тип запроса, и адрес запроса (тип ресурса и его идентификатор, в случае необходимости).
В следующей статье поговорим о "сборниках" на проекте Get My Link, какие виды и зачем они вообще нужны. Так же если успею, то будет первое публичное видео работы нового интерфейса.