Как-то мой друг сказал, что Drupal 8 - это ползающий ребенок, который не понимает, что происходит вокруг. За этим смешно наблюдать, но всегда нужно быть на чеку.
В общем-то, он прав. Но я бы хотел поделиться чем-то, что мне нравится и что уже успешно применено на практике.
Речь пойдет о RESTful Web Services API.
Эта новинка Drupal 8 дает возможность сторонним разработчикам использовать (и изменять) данные приложений. Например, взаимодействие с мобильными приложениями или фронтэнд построен таким образом, что от сервера требуются только данные, а отрисовка HTML происходит на клиенте.
Эти функции как-то в один момент сглаживают неуклюжесть младенца и сразу появляется желание понаблюдать за ним еще, не правда ли? Давайте разбираться дальше.
Методы HTTP
- GET для получения данных (SELECT).
В случае “удачного” (или не содержащего ошибок) адреса, GET возвращается представление ресурса в формате XML или JSON (в зависимости от значения переменной _format) в сочетании с кодом состояния HTTP 200 (OK).
В случае наличия ошибок обычно возвращается код 404 (NOT FOUND) или 400 (BAD REQUEST).
По этому поводу есть отличный пример:
HEADERS: Content-Type: application/json
- POST для добавления данных (INSERT)
При успешном создании ресурса возвращается HTTP код 201, а также в заголовке ‘Location’ передается адрес созданного ресурса.
Пример:
HEADERS:
Content-Type: application/json
Authorization: Basic XXXX
X-CSRF-Token: XXXX - получить его можно по этому пути http://example.com/rest/session/token
BODY:
{
"name":[{"value":"test"}],
"status":[{"value":"1"}],
"mail":[{"value":"test@test.fr"}],
"pass":"test"
}
- PATCH (PUT) для обновления данных (UPDATE).
Если вы использовали PATCH для обновления (и оно прошло успешно), то возвращается код 200 (или 204 если не был передан какой-либо контент в теле ответа). Если PATCH используется для создания экземпляра, то при успешном выполнении обычно возвращается HTTP код 201.
- DELETE для удаления данных.
При успешном удалении возвращается 200 (OK) код HTTP, совместно с телом ответа, содержащим данные удаленного ресурса (отрицательно сказывается на экономии трафика) или завернутые ответы (Смотрите "Возвращаемые данные"). Также возможно использование HTTP кода 204 (NO CONTENT) без тела ответа.
Как происходит вывод articles при помощи views export
Если кто-то давно думал, как же это лучше сделать – я подготовил пошаговую инструкцию.
- Включаем следующие модули "RESTful Web Services" и "Serialization"
- Создаем REST EXPORT views
- Нажать на "Views":
- Нажать "Add new view":
После завершения установки модуля нажмите «Structure» в меню администрирования:
Заполните форму, как показано на скриншоте ниже. Я назвал “Article REST Export”. Выберите "Article" из раскрывающегося списка в types. Поставьте галочку в поле "Provide a REST export" в разделе "REST export settings"./
Далее укажите ссылку в поле "REST export path" по которой будете получать данные. В примере это "rest/export/json/article"
Жмем кнопку "Save and edit" и вы увидите следующую страницу.
Нажмите на "Settings" для выбора формата выходных данных
После сохранения Views вы можете проверить конечную точку с помощью любого клиента REST.
Еще один хороший пример запроса:
HEADERS: Content-Type: application/json
RESPONSE:
Custom REST resource
Для создания своего ресурса с нужными данными нужно:
Создать в модуле по пути /modules/YOUR_MODULE/src/Plugin/rest/resource файл ProgramListResource.php
И прописать следующее:
namespace Drupal\my_module\Plugin\rest\resource;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Psr\Log\LoggerInterface;
use Drupal\my_module\MyApiFetcher;
/**
* Provides a Exercise List Resource
*
* RestResource(
* id = "exercise_list_resource", // Машиное имя
* label = Translation("Exercise List Resource"), // Заголовок
* uri_paths = {
* "canonical" = "/api/v1/exercise/list" // Ссылка по которой будет доступны данные
* }
* )
*/
class ExerciseListResource extends ResourceBase {
/**
* The My API fetcher.
*
* var \Drupal\my_module\MyApiFetcher
*/
protected $myApiFetcher;
/**
* Constructs a new ExerciseListResource instance.
*
* param array $configuration
* A configuration array containing information about the plugin instance.
* param string $plugin_id
* The plugin_id for the plugin instance.
* param mixed $plugin_definition
* The plugin implementation definition.
* param array $serializer_formats
* The available serialization formats.
* param \Psr\Log\LoggerInterface $logger
* A logger instance.
* param \Drupal\my_module\myApiFetcher $my_api_fetcher
* The My API fetcher.
*/
public function __construct(array $configuration, $plugin_id,
$plugin_definition, array $serializer_formats,
LoggerInterface $logger,
MyApiFetcher $slim_api_fetcher) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);
$this->myApiFetcher = $my_api_fetcher; // Динамически подгружаем данные для сбора данных
}
/**
* {inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->getParameter('serializer.formats'),
$container->get('logger.factory')->get('rest'),
$container->get('my_api.fetcher')
);
}
/**
* Responds to entity GET requests.
* return \Drupal\rest\ResourceResponse
*/
public function get() { //Реализация получения (GET) данных
$data = [];
$exercises = $this
->myApiFetcher
->getExercises();
if (!empty($exercises)) {
foreach ($exercises as $exercise) {
$data[] = [ // Запись данных в массив
'exercise_id' => $exercise->id(),
'exercise_title' => $exercise->getName(),
'exercise_count' => $this->myApiFetcher->getFieldValue($exercise, 'exercise_count'),
];
}
}
return new ResourceResponse($data);
}
}
Создать config file где опишем resource.
Назовем файл rest.resource.program_list_resource.yml
Пропишем в его следующее:
plugin_id: program_list_resource
granularity: method
configuration:
GET:
supported_formats: // Поддерживающие форматы данных
- json
supported_auth: // Тип авторизации.
- basic_auth
Пример запроса:
HEADERS: Content-Type: application/json
RESPONSE:
[
{
"program_id": "1",
"program_title": "Program 1",
},
{
"program_id": "2",
"program_title": "Program 2",
}
]
На github есть пример модуля https://github.com/Ruslan03492/rest_api_example
Несмотря на то, что Drupal 8 действительно пока натыкается на все острые углы в доме, у него уже есть какие-то фишки, которые мы можем применять. Что, конечно, не отменяет состояния повышенной внимательности к тому, что происходит вокруг.
Комментарии
На главной.
Пример с POST почему-то с GET.
По сабжу - как вообще реализовывают авторизацию в случае REST?
спасибо. Еще бы пример кейса какого-нибудь из жизни. Вообще бы шикарно было.
Интересно, почему обычный REST, а не jsonapi, например?
POST: https://example.com/user/login?_format=json
Content-type: application/json
{
"name": "admin",
"pass": "password"
}
https://www.drupal.org/docs/8/core/modules/rest/javascript-and-drupal-8-...
по результату получить токен, где-то его хранить и тыкать его в голову))
Отличный клиент для работы с полученным api