28 December 2017

Построение RESTful web API на платформе InterSystems — 2

InterSystems corporate blogAPI

Введение


Четыре года назад я написал свою первую статью на Хабре и она была посвящена созданию RESTful web API на платформе InterSystems. С тех пор прошло немало времени и вышло несколько новых релизов, которые значительно упростили работу по созданию RESTful web API. Вот об этих изменениях я и хочу рассказать в этой статье, а также дать несколько советов по созданию RESTful web API на платформе InterSystems.


Содержание


  • Архитектура RESTful web API
  • Брокеры
  • Разделение брокеров
  • Параметры брокеров
  • Обобщение кода
  • CORS
  • Аутентификация
  • Инструменты отладки и тестирования
  • Примеры
  • JSON
  • Выводы
  • Ссылки

Архитектура RESTful web API


Надеюсь, что читатель знаком с тем что такое RESTful web API и основами его реализации на платформе InterSystems (доступно начиная с версии 2014.1). Этому посвящено много статей/вебинаров/обучающих курсов в частности и моя предыдущая статья. В любом случае первое с чего хотелось бы начать это общая высокоуровневая архитектура вашего приложения, включающего RESTful web API. Выглядеть она может следующим образом:



На этой схеме представлены основные уровни вашего решения:


Данные


Хранимые классы на платформе InterSystems.


Терминальное API


Слой взаимодействия с данными. Данные не должны изменяться иначе, чем через это API.
Методы этого API не пишут на устройство. Терминальное API может возвращать:


  • Объект
  • Статус или исключение (в зависимости от ваших предпочтений)

Web API


Преобразует входящий запрос в форму, понимаемую терминальным API и вызывает методы терминального API. Результата выполнения терминального API возвращаются клиенту.
Web API не взаимодействует с данными напрямую. Употребляю термин Web API а не RESTful web API, т.к. Web API может быть реализовано с применением иной архитектуры, например на основе протокола WebSocket который также поддерживается платформой InterSystems, о чём уже писали на Хабре и не раз.


Клиент


Как правило JavaScript (но совсем необязательно) приложение доступное конечному пользователю. Этот уровень не должен иметь прямых связей с базой данных, быть нагруженным основной бизнес-логикой и хранить состояние приложения. На этот уровень обычно выносится только простейшая бизнес-логика: интерфейс авторизации, проверка вводимых значений на допустимость и соответствие формату, несложные операции с данными (сортировка, группировка, подсчёт значений), уже загруженными на клиент.


Подобное разделение увеличивает конфигурируемость приложения, облегчает его отладку, поиск и исправление ошибок. По сути это трёхуровневая архитектура построения приложений.


Брокеры


Брокеры это классы, содержащие логику вашего RESTful web API. Они:


  • Наследуются от %CSP.REST
  • Содержит пути – сопоставления URI и вызываемых методов

Пример пути:


<Route 
  Url="/path/:param1/:param2" 
  Method="GET" 
  Call="Package.Class:ClassMethod" 
/>

Где ClassMethod – любой метод класса.


Разделение брокеров


«Физическое» разделение


Так как в RESTful web API может быть много путей — методов, один брокер скоро будет перегружен методами. Чтобы этого не произошло разделяйте брокеры на несколько классов следующим образом:
Разделение брокеров


Где:


  • Абстрактный брокер отвечает за преобразование запросов, CORS и прочие технические моменты не связанные с логикой RESTful web API.
  • Брокеры 1..N собственно содержит методы, обрабатывающие запросы (вызывающие методы терминального API и возвращающие ответы терминального API клиенту).

«Логическое» разделение и версионирование


Обычно Брокеры содержит пути – сопоставления URI и вызываемых методов, но кроме путей брокеры могут «передавать» запросы друг другу. Выглядит это так:


<Map Prefix="/form" Forward="Destination.Broker"/>

Это позволяет провести разделение брокеров по предметным областям с которыми они связаны, а также обеспечить версионирование API:


Логическое разделение брокеров


Параметры брокеров


Вот параметры которые рекомендуется установить в брокерах вашего RESTful web API:


Parameter CONTENTTYPE = {..#CONTENTTYPEJSON};
Parameter CHARSET = "UTF-8";
Parameter UseSession As BOOLEAN = 1;

Вот за что они отвечают:


  • CONTENTTYPE — добавляет во все ответы сервера информацию о том, что ответ будет в формате JSON.
  • CHARSET — конвертирует ответ в формат UTF8.
  • UseSession — использует сессию для запросов пользователя. Подробнее об этом в разделе аутентификация.

Так как все брокеры наследуются от одного абстрактного брокера, то эти параметры достаточно указать один раз в абстрактном брокере (наследуются только параметры первого суперкласса).


Обобщение кода


Одна из проблем, часто возникающих при написании RESTful web API это копипаста кода из брокера в брокер, что создаёт большое число путей и строк кода. Для избежания этого рекомендую использовать кодогенерацию совместно с пакетом %Dictionary содержащим всю метаинформацию необходимую для написания метод-генераторов. Примером активного использования кодогенерации является библиотека RESTForms. Кроме того использование кодогенерации позволяет достичь большего единообразия вашего RESTful web API.


CORS


Технология современных браузеров, которая позволяет предоставить веб-странице доступ к ресурсам другого домена. Для включения доступа к вашему RESTful web API с использованием CORS добавьте в брокер параметр:


Parameter HandleCorsRequest = 1;

Что предоставит доступ с любого другого домена. Это небезопасно и поэтому надо также переопределить метод OnHandleCorsRequest, его сигнатура:


ClassMethod OnHandleCorsRequest(pUrl As %String) As %Status {}

Этот метод должен проверять Origin запроса, к примеру он должен совпадать с именем хоста веб-приложения. Для получения Origin можно использовать вот такой метод:


ClassMethod GetOrigins() As %String
{
    set url = %request.GetCgiEnv("HTTP_REFERER")
    return $p(url,"/",1,3) // get http(s)://origin.com:port
}

Аутентификация


Для того чтобы один пользователь потреблял одну лицензию и работал в рамках одной сессии нужно сконфигурировать в Портале Управления Системой ваши REST и CSP приложения так, чтобы выполнялись условия:


  1. Во всех брокерах Parameter UseSession = 1;.
  2. Все веб приложения доступны только с аутентификацией.
  3. У всех веб приложений установлен таймаут сессии (900, 3600).
  4. У всех приложений установлено одно значение GroupById.
  5. У всех приложений установлено одно значение Cookie Path.

Инструменты отладки и тестирования


Для отладки можно использовать такие внешние средства как:


  • REST клиент (например Postman) — первоочередной инструмент отладки RESTful web API позволяет сохранять и документировать запросы, форматировать JSON ответы, выполнять запросы к нескольким окружениям и предоставляет многие другие удобства для разработчика.
  • Перехватывающий прокси-сервер (например Fiddler) — позволяет перехватывать, отображать, редактировать и дублировать запросы к RESTful web API.
  • Анализатор трафика (например WireShark) — помогает в случаях битых пакетов, проблем с кодировками, необходимостью анализа удалённой системы и прочими ситуациями когда вышеназванных инструментов недостаточно.

Настоятельно не рекомендую использовать инструменты командной строки, такие как curl и wget.


Подробно внешние и внутренние средства отладки описаны в серии статей (Часть 1 — внешние средства, Часть 2 — внутренние средства) на InterSystems Developer Community.


Примеры


Приведу несколько примеров RESTful web API.


MDX2JSON и клиент DeepSeeWeb


MDX2JSON — RESTful web API предоставляет информацию о кубах, пивотах, дашбордах и многих других элементах DeepSee, в частности — результатах исполнения MDX запросов, что позволяет встраивать пользовательский интерфейс аналитического решения на DeepSee в любое современное Web или мобильное приложение. Работает начиная с версии 2014.1.
DeepSeeWeb — AngularJS приложение, предоставляющее альтернативную реализацию портала пользователя DeepSee. Может быть легко кастомизирован. Использует MDX2JSON в качестве бэкэнда. Вот пример дашборда визуализированного в DeepSeeWeb:


DeepSeeWeb


Подробная статья про DeepSee.


EnsembleWorkflow и клиент EnsembleWorkflowUI


В интеграционной платформе InterSystems есть подсистема Ensemble Workflow, позволяющая людям участвовать в автоматизированных бизнес-процессах. Ensemble Workflow RESTful web API и клиент EnsembleWorkflowUI. RESTful web API предоставляет доступ к задачам пользователя. Работает начиная с версии 2014.1. Вот так выглядит визуализация:


EnsembleWorkflowUI


EnsembleWorkflowUI


RESTForms


RESTForms — универсальный RESTful web API бэкэнд работы с данными на платформе InterSystems 2016.1+ для современных веб-приложений.


Вот часть путей, доступных в RESTForms:


URL Описание
info Список классов
info/all Метаинформация всех классов
info/:class Метаинформация одного класса
object/:class/:id Получить объект
object/:class/:id/:property Получить свойство объекта
object/:class Создать объект
object/:class/:id Обновить объект из динамического объекта
object/:class Обновить объект из объекта класса
object/:class/:id Удалить объект
objects/:class/:query Выполнить SQL запрос

В этом проекте активно используется обобщение кода (с помощью кодогенерации и использования пакета %Dictionary).


Доступны клиенты на Angular и React, выглядит это так:


список классов


JSON


JavaScript Object Notation — текстовый формат обмена данными, использующийся совместно с RESTful web API. Поддержка JSON на платформе InterSystems появилась начиная с версии 2009.2, но была значительно улучшена к версии 2016.2. Подробнее об использовании JSON можно почитать в документации.


Выводы


  • REST на сегодня – основная и общепринятая методика построения API для сети интернет
  • Предоставляя RESTful web API вы получаете возможность выбора из огромного набора технологий построения клиентских приложений, в том числе:
    • JavaScript (AngularJS, React, extJS, ...)
    • Мобильные приложения (Cordova и подобные, Native)
  • Технологии InterSystems позволяют вам с лёгкостью создавать RESTful web API.

Ссылки


Tags:intersystems cacheintersystemsrest apirestwebrestfulrestful api
Hubs: InterSystems corporate blog API
+15
3.3k 22
Comments 2