RESTful API в MODX Rrevolution
В MODX 2.3 был замечен удобный способ разработки API-интерфейсов RESTful поверх MODX. Это делается с поддержкой класса modRestService и производных modRestController. Он поддерживает большое количество интересных функций для взаимодействия с экземплярами xPDOObject. Цель этого документа - предоставить вам информацию, нужную для создания собственного API.
В кратце
- Создайте файл index.php, который обрабатывает загрузку MODX, настраивает службу REST с правильной конфигурацией и передает запрос контроллеру.
- Создайте файл .htaccess, который направляет все запросы (в поддиректории или в конкретном домене) в index.php
- Создайте контроллеры для каждой из ваших конечных точек
Создание обработчика загрузки MODX
Классы modRestService
и modRestController
значительно облегчат вашу работу, но вам нужно настроить некоторый базовый код для его подключения. Для этого документа мы предполагаем, что вы помещаете свой API в папку /rest/
, при необходимости корректируйте пути.
Сначала создайте файл rest/index.php
, который выглядит примерно так:
<?php
// Загрузить MODX
require_once dirname(dirname(__FILE__)) . '/config.core.php';
require_once MODX_CORE_PATH . 'model/modx/modx.class.php';
$modx = new modX();
$modx->initialize('web');
$modx->getService('error','error.modError', '', '');
// Загрузить любые классы или пакеты (модели), которые вам потребуются
$path = $modx->getOption('mypackage.core_path', null,
$modx->getOption('core_path').'components/mypackage/') . 'model/mypackage/';
$modx->getService('mypackage', 'myPackage', $path);
// Загрузить класс modRestService и передать ему некоторую базовую конфигурацию
$rest = $modx->getService('rest', 'rest.modRestService', '', array(
'basePath' => dirname(__FILE__) . '/Controllers/',
'controllerClassSeparator' => '',
'controllerClassPrefix' => 'MyController',
'xmlRootNode' => 'response',
));
// Подготовить запрос
$rest->prepare();
// Удостовериться, что пользователю предоставлены необходимые права доступа; вернуть пользователю ошибку 401 в обратном случае
if (!$rest->checkPermissions()) {
$rest->sendUnauthorized(true);
}
// Выполнить запрос
$rest->process();
?>
После этого вам необходимо убедиться, что все запросы к вашей папке /rest/
действительно обрабатываются сервером REST. Чтобы сделать это, добавьте следующее в ваш.htaccess
(или эквивалент в nginx или других системах) в корне вашего сайта:
Настройка сервера на Apache
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-s
RewriteRule ^(.*)$ rest/index.php?_rest=$1 [QSA,NC,L]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.*)$ rest/index.php [QSA,NC,L]
Настройка сервера на NGINX
location /rest/ {
try_files $uri @modx_rest;
}
location @modx_rest {
rewrite ^/rest/(.*)$ /rest/index.php?_rest=$1&$args last;
}
Ежели вы незамедлительно обнаружите /rest/foobar в вашем браузере, вы должны унаследовать ошибку, что показывает на то, что ваш API работает.
{
success: false,
message: "Method not allowed",
object: [ ],
code: 405
}
Теперь мы можем начать с фактической разработки API!
Точки доступа к API
Действительный API складывается изо много окончательных точек. Ежели вы желаете организовать безукоризненный RESTful API, всякая окончательная крапинка будет согласоваться «ресурсу» (не безоговорочно варианту изо левосторонного древа MODX! ), И различные HTTP-глаголы (GET, POST, PUT и DELETE) будут употребляться ради взаимодействия с определенными объектами. Допустим, вы создаете API ради управления перечнем дел, у вас могут являться «элементы» окончательной точки с последующими действиями:
-
GET /items
: возвращает элементы в вашем списке дел -
GET /items/15
: возвращает элемент с первичным ключом 15 -
POST /items
: создать новый элемент в списке дел -
PUT /items/15
: обновить одно или несколько значений в вашем списке дел с помощью первичного ключа 15 -
DELETE /items/15
: удалить элемент с помощью первичного ключа 15
В глобальной сети интернет видимо-невидимо противоречат про то, как назвать ваши окончательные точки - в данном случае мы облюбовали многочисленные «пункты». Стоит заметить, что у нас нет окончательных точек, в том числе /items/create, - такое уже покрыто POST ради /items и представляется основным аспектом учения API RESTful.
Дабы организовать окончательную точку ингредиентов (items), вам необходимо организовать регулятор ингредиентов (items controller). Как следует из конфигурации, какую мы дали в modRestService ранее, и значений по умолчанию, всякий регулятор вынужден завязываться с MyController, укладываться в указатель /rest/Controllers/
, а файл вынужден согласоваться имени окончательной точки с суффиксом .php
. Оттого сотворите новоизобретенный документ /rest/Controllers/Items.php
и скопируйте в него поступающий код:
class MyControllerItems extends modRestController {
public $classKey = 'ToDoItem';
public $defaultSortField = 'sortorder';
public $defaultSortDirection = 'ASC';
}
Предполагая, что ToDoItem представляется именованием позволительного выводного xPDOObject, и вы навалили его где-то с поддержкой $modx-> addPackage() (например, в свой разряд Service, некоторый мы вытребовали в index. php), сейчас у вас есть абсолютно многофункциональный RESTful API для ваших предметов ToDoItem. Элементарно спросите /rest/items, и данный требование обязан отдавать ваши ToDoItems в привлекательном формате JSON.
Если у вас нет готового пакета, вы также можете установить для свойства classKey значение «modResource» и для defaultSortField значение «id», чтобы настроить API для всех ресурсов.
{
results: [
{
id: 1,
sortorder: 1,
name: "Заканчиваем документировать RESTful API",
added: "2020-05-14",
target_completion_date: "2020-05-14",
assigned_to: ""
},
// ...
],
total: 1
}
Это как волшебство! Но вы знаете, что еще лучше? Это полноценный API сейчас... И если вы вернетесь к действиям, которые мы упоминали ранее, все они будут работать "из коробки". Например, /rest/items/1
, вернет только элемент to do с идентификатором 1. Чтобы проверить POST, PUT и DELETE, вам, вероятно, потребуется использовать что-то вроде Postman или curl для отправки правильных запросов, но теперь они также должны быть функциональными.
Теперь, когда у вас работает базовый API, пришло время приступить к реальной разработке и заставить ее работать так, как вы хотите.
Улучшаем работу с точками доступа к API
Большая часть следующей работы сводится к тому, чтобы сделать ваши конечные точки более умными и добавить их больше. Возможно, вы захотите изменить способ возврата ваших данных, отфильтровать ненужные данные и многое другое. У ModRestController есть все опции и хуки для вас, чтобы сделать это.
Каждый из запросов передается определенному методу в вашем контроллере. Это означает, что когда вы, например, запрашиваете GET /items
, который возвращает список объектов, он обрабатывается методом modRestController.getList()
. Вот как запросы направляются на контроллер:
- GET /items:
modRestController.get()
, который вызываетmodRestController.getList()
- GET /items/5:
modRestController.get()
, который вызываетmodRestController.read()
- POST /items:
modRestController.post()
- PUT /items/5:
modRestController.put()
- DELETE /items/5:
modRestController.delete()
Эти методы по умолчанию делают то, что вы ожидаете от них, с некоторой разумной обработкой ошибок и - по большей части - не нуждаются в настройке. Существуют также такие методы, как modRestController.beforePost()
, modRestController.beforePut()
, modRestController.beforeDelete()
, которые позволяют предотвратить действие (создание, обновление или удаление объекта соответственно) путем возврата false. Обсуждаемый объект доступен через $this->object
, так что вы можете убедиться, что у пользователя есть разрешение на выполнение действия или другую подготовку. Существует также modRestController.afterRead()
, modRestController.afterPost()
, modRestController.afterPut()
и modRestController.afterDelete()
для выполнения действий после завершения действия. Этим методам передается массив по ссылке, который содержит объект, который должен быть возвращен.