Этот текст - перевод статьи из нового портала документации для разработчиков Joomla, раздел "Основные концепции". Ранее уже был опубликован перевод раздела, описывающего принципы Dependency Injection Containers в Joomla 4.


Концепция веб-сервисов

  • Веб-сервисы используются для взаимодействия различных систем друг с другом с помощью протокола HTTP, а в настоящее время и через TLS (безопасность транспортного уровня).

  • Веб-сервисы действуют как контракт между поставщиком сервиса и потребителем сервиса через Endpoint.

  • Веб-сервисы подобны дверям и окнам в доме, они являются ВХОДАМИ (inputs) и ВЫХОДАМИ (outputs) во ВНЕШНИЙ мир.

  • В контексте Joomla как системы в целом, Joomla Web services API позволяет Joomla взаимодействовать с внешними источниками данных. Например, веб-приложениями, мобильными приложениями и т.д.

Взаимодействие с Web Services API Joomla 4.x

Взаимодействие с API веб-сервисов Joomla 4 происходит через определённые endpoint'ы:

Использование Joomla API

Чаще всего, при использовании Joomla API, под капотом по-прежнему используется cURL или php. Чаще всего cURL доступен на Вашем хостинге. В противном случае проверьте с помощью phpinfo();

Определим переменные

Сначала мы определим некоторые переменные, которые будем использовать во всех наших запросах:

  • URL нашего сайта на Joomla 4.x

  • Токен Joomla API учетной записи суперпользователя или учетной записи, у которой есть, по крайней мере, разрешение core.login.api и core.login.site, чтобы иметь возможность видеть изменение токена текущего пользователя, вошедшего в систему.

<?php
// Before passing the HTTP METHOD to CURL
use Joomla\Http\HttpFactory;
use Joomla\Uri\Uri;

$http = (new HttpFactory())->getAvailableDriver();
$url   = 'https://example.org/api/index.php/v1';
$uri  = new Uri($url);

// Поместите Ваш токен Joomla! Api token в безопасное место,
// например, в менеджер паролей или хранилище.
// Мы не рекомендуем использовать переменные окружения
// для хранения паролей.
// Здесь описано почему: https://www.trendmicro.com/en_us/research/22/h/analyzing-hidden-danger-of-environment-variables-for-keeping-secrets.html

$token = '';

[Статья Создание внешних запросов с использованием HttpFactory (Joomla) на Хабре - Т.С.]

Поместите Ваш токен Joomla! Api token в безопасное место, например, в менеджер паролей или хранилище. Мы не рекомендуем использовать переменные окружения для хранения паролей. Здесь описано почему - статья "Analyzing the Hidden Danger of Environment Variables for Keeping Secrets" на TrendMicro.com.

POST - Создание материала Joomla в категории "Uncategorized" ("Без категории") по REST API (ID категории = 2)

<?php
use Joomla\Http\HttpFactory;
use Joomla\Uri\Uri;

$http = (new HttpFactory())->getAvailableDriver();
$url   = 'https://example.org/api/index.php/v1';
$uri  = new Uri($url);

$token = '';

$categoryId = 2; // Категория "Без категории" Joomla по умолчанию

$data = [
'title'       => 'Как добавить материал Joomla с помощью REST API?',
'alias'       => 'кak-dobavit-material-joomla-s-pomoshhju-rest-api',
'articletext' => 'Я пока не знаю... Поищу-ка я новенькие статьи о Joomla на Хабре.',
'catid'       => $categoryId,
'language'    => '*',
'metadesc'    => '',
'metakey'     => '',
];

$dataString = json_encode($data);

// HTTP request headers
$headers = [
'Accept: application/vnd.api+json',
'Content-Type: application/json',
'Content-Length: ' . mb_strlen($dataString),
sprintf('X-Joomla-Token: %s', trim($token)),
];

// Таймаут в секундах
$timeout = 30;

// Установите endpoint для работы с материалами.
// Это часть $uri.
$uri->setPath('content/articles');

// Это будет PSR-7 совместимый Response
$response = $http->request('POST', $uri, $dataString, $headers, $timeout);

// В результате запроса мы имеем stream, поэтому делаем просто:
echo $response->body;

Небольшое отступление о классе Uri в Joomla (от переводчика)

Для большего понимания происходящего в коде и дальнейшей более удобной работы с Joomla API позволю себе внедрить краткую справку о классах Uri в Joomla:

  • Официальная документация Joomla по классу Joomla\Uri\Uri

  • Доки для Joomla 3, но класс Uri в Joomla 4 остался в целом тем же.

  • В документации по ссылке указан класс Joomla\CMS\Uri\Uri, который расширяет класс Joomla\Uri\Uri, который в свою очередь, расширяет класс Joomla\Uri\AbstractUri. Методы родительского класса доступны в дочернем.

  • Класс Joomla\Uri\Uri предназначен для работы с url и позволяет работать с ним как с объектом: $url->setPath, $url->setScheme, $url->setScheme , $url->setScheme и другими методами (список смотрим в файле класса: libraries/vendor/joomla/uri/src/Uri.php). Соответствующие геттеры заданы в классе Joomla\Uri\AbstractUri

  • Класс Joomla\CMS\Uri\Uri добавляет несколько методов, которые необходимы для больше внутренней работы Joomla: определение внешний ли или внутренний url, текущий url без GET-параметров и т.д.

GET - Получение списка всех материалов Joomla из категории "Uncategorized" ("Без категории")

<?php
use Joomla\Http\HttpFactory;
use Joomla\Uri\Uri;

$http = (new HttpFactory())->getAvailableDriver();
$url   = 'https://example.org/api/index.php/v1';
$uri  = new Uri($url);

$token = '';

$categoryId = 2; // Категория "Без категории" Joomla по умолчанию

// Не будем отправлять payload на сервер
$dataString = null;

// HTTP заголовки запроса
$headers = [
'Accept: application/vnd.api+json',
'Content-Type: application/json',
sprintf('X-Joomla-Token: %s', trim($token)),
];

// Таймаут в секундах
$timeout = 30;

// Установите endpoint для работы с материалами.
// Это часть $uri.
$uri->setPath('content/articles');

// Это будет PSR-7 совместимый Response
$response = $http->request('GET', $uri, $dataString, $headers, $timeout);

// В результате запроса мы имеем stream, поэтому делаем просто:
echo $response->body;

GET - Получение материала Joomla по id (REST API)

<?php
use Joomla\Http\HttpFactory;
use Joomla\Uri\Uri;

$http = (new HttpFactory())->getAvailableDriver();
$url   = 'https://example.org/api/index.php/v1';
$uri  = new Uri($url);

$token = '';

$articleId = 1; // ID нужной статьи в Joomla

// Не будем отправлять payload на сервер
$dataString = null;

// HTTP заголовки запроса
$headers = [
'Accept: application/vnd.api+json',
'Content-Type: application/json',
sprintf('X-Joomla-Token: %s', trim($token)),
];

// Таймаут в секундах
$timeout = 30;

// Устанавливаем path-часть Url для получения конкретного материала.
$uri->setPath(sprintf('content/articles/%d', $articleId));

// Это будет PSR-7 совместимый Response
$response = $http->request('GET', $uri, $dataString, $headers, $timeout);

// В результате запроса мы имеем stream, поэтому делаем просто:
echo $response->body;

PATCH - Изменение материала Joomla по id (REST API)

<?php
use Joomla\Http\HttpFactory;
use Joomla\Uri\Uri;

$http = (new HttpFactory())->getAvailableDriver();
$url   = 'https://example.org/api/index.php/v1';
$uri  = new Uri($url);

$token = '';
$articleId = 1; // ID нужной статьи в Joomla

$data = [
'id'          => $articleId,
'title'       => 'Как добавить материал Joomla с помощью REST API?',
'introtext' => 'При использовании PATCH текст статьи должен быть разделен на две части или использовать, по крайней мере, только introtext, чтобы сохранить данные должным образом',
'fulltext' => 'Больше контента богу контента!',
];

$dataString = json_encode($data);

// HTTP заголовки запроса
$headers = [
'Accept: application/vnd.api+json',
'Content-Type: application/json',
'Content-Length: ' . mb_strlen($dataString),
sprintf('X-Joomla-Token: %s', trim($token)),
];

// Таймаут в секундах
$timeout = 30;

// Устанавливаем path-часть Url для изменения конкретного материала.
$uri->setPath(sprintf('content/articles/%d', $articleId));

// Это будет PSR-7 совместимый Response
$response = $http->request('PATCH', $uri, $dataString, $headers, $timeout);

// Здесь получим status code запроса
echo $response->code;

Примечание переводчика о структуре сущности материала Joomla

Примечание переводчика для разработчиков, не знакомых со структурой компонента материалов (com_content) Joomla. Каждый материал (article) имеет вступительный текст и вводный текст. Вступительный текст отображается в списке материалов в виде блога (с картинкой вступительного текста, парой абзацев и кнопкой "подробнее"). Полный текст материала отображается, соответственно, когда пользователь хочет читать статью полностью и открывает её.

В базе данных в таблице для материалов Joomla реализовано 2 ячейки: introtext и fulltext типа MEDIUMTEXT соответственно.

Если контент-менеджер с помощью вставки линии "подробнее" в админке указал Joomla, что текст нужно разбить на вступительную и полную часть, то текст будет разрезан на 2 части и каждая из частей будет храниться в своей ячейке. Если же линия "подробнее" не вставлена, то весь текст хранится в ячейке introtext.

Таким образом при работе с REST API нужно представлять КАК происходит работа с текстом на всех этапах: создание, редактирование, отображение редактору, отображение пользователю сайта. Если Joomla используется как бэкенд, а фронт - это мобильное приложение или фронт сделан на js-фреймворке, то отображение зависит уже не от Joomla, а от реализации приложения и тогда весь текст материала можно хранить в introtext. Если же REST API используется при редактировании, а для посетителей используется HTML-вывод Joomla, то соблюдение правил игры CMS будет важным, так как это будет влиять на отображение для пользователей сайта.

DELETE - Удаление материала Joomla по id (REST API)

<?php
use Joomla\Http\HttpFactory;
use Joomla\Uri\Uri;

$http = (new HttpFactory())->getAvailableDriver();
$url   = 'https://example.org/api/index.php/v1';
$uri  = new Uri($url);

$token = '';
$articleId = 1; // ID нужной статьи в Joomla

// Не будем отправлять payload на сервер
$dataString = null;

// HTTP заголовки запроса
$headers = [
'Accept: application/vnd.api+json',
'Content-Type: application/json',
sprintf('X-Joomla-Token: %s', trim($token)),
];

// Таймаут в секундах
$timeout = 30;

// Устанавливаем path-часть Url для удаления конкретного материала.
$uri->setPath(sprintf('content/articles/%d', $articleId));

// Это будет PSR-7 совместимый Response
$response = $http->request('DELETE', $uri, $dataString, $headers, $timeout);

// Здесь получим status code запроса
echo $response->code;

Запросы к REST API Joomla с использованием чистого PHP cURL

Перед использованием этого кода удостоверьтесь, что cURL установлен на Вашем хостинге, проверьте с помощью phpinfo(). [Данный раздел документации может пригодится для non-Joomla сайтов, которые будут взаимодействовать с Joomla 4+ сайтами - Т.С.]

Определим переменные

Сначала мы определим некоторые переменные, которые будем использовать во всех наших cURL  запросах:

  • URL нашего сайта на Joomla 4.x

  • Токен Joomla API учетной записи суперпользователя или учетной записи, у которой есть, по крайней мере, разрешение core.login.api и core.login.site, чтобы иметь возможность видеть изменение токена текущего пользователя, вошедшего в систему.

<?php
// Before passing the HTTP METHOD to CURL
$curl  = curl_init();

$url   = 'https://example.org/api/index.php/v1';

// Поместите Ваш токен Joomla! Api token в безопасное место,
// например, в менеджер паролей или хранилище.
// Мы не рекомендуем использовать переменные окружения
// для хранения паролей.
// Здесь описано почему: https://www.trendmicro.com/en_us/research/22/h/analyzing-hidden-danger-of-environment-variables-for-keeping-secrets.html
$token = '';

POST - Создание материала Joomla в категории "Uncategorized" ("Без категории") по REST API с помощью cURL

<?php
// Before passing the HTTP METHOD to CURL
$curl  = curl_init();

$url   = 'https://example.org/api/index.php/v1';

$token = '';

$categoryId = 2; // Joomla's default "Uncategorized" Category


$data = [
'title'       => 'How to add an article to Joomla via the API?',
'alias'       => 'how-to-add-article-via-joomla-api',
'articletext' => 'I have no idea...',
'catid'       => $categoryId,
'language'    => '*',
'metadesc'    => '',
'metakey'     => '',
];

$dataString = json_encode($data);

// HTTP request headers
$headers = [
'Accept: application/vnd.api+json',
'Content-Type: application/json',
'Content-Length: ' . mb_strlen($dataString),
sprintf('X-Joomla-Token: %s', trim($token)),
];

curl_setopt_array($curl, [
        CURLOPT_URL            => sprintf('%s/%s',$url,'content/articles'),
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING       => 'utf-8',
        CURLOPT_MAXREDIRS      => 10,
        CURLOPT_TIMEOUT        => 30,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_HTTP_VERSION   => CURL_HTTP_VERSION_2TLS,
        CURLOPT_CUSTOMREQUEST  => 'POST',
        CURLOPT_POSTFIELDS     => $dataString,
        CURLOPT_HTTPHEADER     => $headers,
    ]
);

$response = curl_exec($curl);
curl_close($curl);
echo $response;

GET - Получение списка всех материалов Joomla из категории "Uncategorized" ("Без категории") с помощью cURL по REST API

<?php
// Before passing the HTTP METHOD to CURL
$curl  = curl_init();

$url   = 'https://example.org/api/index.php/v1';

$token = '';

$categoryId = 2; // Joomla's default "Uncategorized" Category


// HTTP request headers
$headers = [
'Accept: application/vnd.api+json',
'Content-Type: application/json',
sprintf('X-Joomla-Token: %s', trim($token)),
];

curl_setopt_array($curl, [
        CURLOPT_URL            => sprintf('%s/content/articles?filter[category]=%d',$url,$categoryId),
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING       => 'utf-8',
        CURLOPT_MAXREDIRS      => 10,
        CURLOPT_TIMEOUT        => 30,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_HTTP_VERSION   => CURL_HTTP_VERSION_2TLS,
        CURLOPT_CUSTOMREQUEST  => 'GET',
        CURLOPT_HTTPHEADER     => $headers,
    ]
);

$response = curl_exec($curl);
curl_close($curl);
echo $response;

GET - Получение конкретного материала Joomla по id с помощью cURL (REST API)

<?php
// Before passing the HTTP METHOD to CURL
$curl  = curl_init();

$url   = 'https://example.org/api/index.php/v1';

$token = '';

$articleId = 1; // The Article ID of a specific Article


// HTTP request headers
$headers = [
'Accept: application/vnd.api+json',
'Content-Type: application/json',
sprintf('X-Joomla-Token: %s', trim($token)),
];
curl_setopt_array($curl, [
        CURLOPT_URL            => sprintf('%s/content/articles/%d',$url,$articleId),
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING       => 'utf-8',
        CURLOPT_MAXREDIRS      => 10,
        CURLOPT_TIMEOUT        => 30,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_HTTP_VERSION   => CURL_HTTP_VERSION_2TLS,
        CURLOPT_CUSTOMREQUEST  => 'GET',
        CURLOPT_HTTPHEADER     => $headers,
    ]
);

$response = curl_exec($curl);
curl_close($curl);
echo $response;

PATCH - Изменение материала Joomla по id с помощью cURL (REST API)

<?php
// Before passing the HTTP METHOD to CURL
$curl  = curl_init();

$url   = 'https://example.org/api/index.php/v1';

$token = '';

$articleId = 1; // The Article ID of a specific Article


$data = [
'id'          => $articleId,
'title'       => 'How to add an article via the Joomla 4 API?',
'introtext' => 'When using PATCH, articletext MUST be splitted in two parts or use at least just introtext in order to work properly',
'fulltext' => 'MORE CONTENT if you wish',
];

$dataString = json_encode($data);

// HTTP request headers
$headers = [
'Accept: application/vnd.api+json',
'Content-Type: application/json',
'Content-Length: ' . mb_strlen($dataString),
sprintf('X-Joomla-Token: %s', trim($token)),
];

curl_setopt_array($curl, [
        CURLOPT_URL            => sprintf('%s/content/articles/%d',$url,$articleId),
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING       => 'utf-8',
        CURLOPT_MAXREDIRS      => 10,
        CURLOPT_TIMEOUT        => 30,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_HTTP_VERSION   => CURL_HTTP_VERSION_2TLS,
        CURLOPT_CUSTOMREQUEST  => 'PATCH',
        CURLOPT_POSTFIELDS     => $dataString,
        CURLOPT_HTTPHEADER     => $headers,
    ]
);

$response = curl_exec($curl);
curl_close($curl);
echo $response;

DELETE - Удаление материала Joomla по id с помощью cURL (REST API)

<?php
// Before passing the HTTP METHOD to CURL
$curl  = curl_init();

$url   = 'https://example.org/api/index.php/v1';

$token = '';

$articleId = 1; // The Article ID of a specific Article


// HTTP request headers
$headers = [
'Accept: application/vnd.api+json',
'Content-Type: application/json',
sprintf('X-Joomla-Token: %s', trim($token)),
];

curl_setopt_array($curl, [
        CURLOPT_URL            => sprintf('%s/content/articles/%d',$url,$articleId),
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING       => 'utf-8',
        CURLOPT_MAXREDIRS      => 10,
        CURLOPT_TIMEOUT        => 30,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_HTTP_VERSION   => CURL_HTTP_VERSION_2TLS,
        CURLOPT_CUSTOMREQUEST  => 'DELETE',
        CURLOPT_HTTPHEADER     => $headers,
    ]
);

$response = curl_exec($curl);
curl_close($curl);
echo $response;

Полезные ресурсы

Ресурсы Joomla сообщества:

Joomla в Telegram:

Комментарии (3)


  1. Sulpher
    24.07.2023 08:19

    Это довольно интересно.
    Можно организовать передачу данных в приложение. А обратно тоже через REST API гоняется? например, в приложении редактируешь новость, данные посылаются на сайт и публикуется материал?


    1. zikkuratvk
      24.07.2023 08:19

      все может :-)


  1. b2z
    24.07.2023 08:19

    Прекрасно! Спасибо.