Модуль обеспечивает взаимодействие интернет-магазина с внешними приложениями посредством публичных методов API. Любой сторонний модуль может привнести собственные методы или откорректировать результат работы "чужого" метода с помощью обработки событий.
Модуль автоматически формирует справку на всех задействованных языках и по всем версиям доступных методов API на основе PHPDoc комментариев. Справка будет доступна по адресу, если соответствующая опция включена в настройках модуля:
http://ваш-домен.ру/api[-ВАШ API КЛЮЧ]/help/<br> Пример 1(если API ключ пустой): http://full.readyscript.ru/api/help Пример 2(если API ключ = 123): http://full.readyscript.ru/api-123/help
Чтобы обратиться к методу API, необходимо выполнить POST или GET запрос на адрес конкретного API метода.
http://ваш-домен.ру/api[-ВАШ API КЛЮЧ]/methods/группа метода.действие метода<br> Пример 1(если API ключ пустой): http://full.readyscript.ru/api/methods/oauth.token?v=V&lang=LANGUAGE&PARAMETERS... Пример 2(если API ключ = 123): http://full.readyscript.ru/api-123/methods/oauth.token?v=V&lang=LANGUAGE&PARAMETERS...
где:
В случае использования POST запроса, обязательно следует передавать заголовок:
Content-type: application/x-www-form-urlencoded
В ответ на запрос вы получите результат в формате JSON.
Для начала работы модуля, необходимо произвести его настройку в разделе Веб-сайт → Настройка модулей → Внешнее API. Модуль имеет следующие опции:
Вкладка "Основные"
Вкладка "Разрешенные методы API"
На данной вкладке отображаются все имеющиеся в системе методы API, есть возможность указать те методы, которые должны быть доступны для вызова и отображения в справочном разделе.
Рассмотрим пример создания собственного метода API news.getList на основе простейшего модуля ModuleName. Предположим, что наш метод API должен возвращать данные в формате JSON о новостях для авторизованного пользователя.
Модуль ModuleName должен быть создан и установлен предварительно. Для того, чтобы модуль ModuleName привнес в систему новый API метод, необходимо создать класс в заранее установленном пространстве имен. Имя API метода состоит из двух символьных идентификаторов Группы и Действия, например: order.getList или order.update. Общая маска имени класса метода API выглядит следующим образом:
\ModuleName\Model\ExternalApi\ГРУППА МЕТОДА\ДЕЙСТВИЕ МЕТОДА
Согласно данной маске, необходимо создать файл getlist.inc.php в папке /modules/modulename/model/externalapi/news, в котором мы разместим наш класс.
Перед созданием класса нашего метода API, необходимо выбрать подходящий родительский класс в зависимости от задач метода. ExternalApi предлагает несколько базовых классов для API (нажав на каждый базовый класс, вы перейдете в дерево наследования, из которого легко можно найти и посмотреть пример кода реальных классов-потомков):
ExternalApi::Model::AbstractMethods::AbstractAuthorizedMethod - для выполнения такого метода требуется авторизационный токен либо обязательно либо опционально для доступа к расширенным данным.
Обязательные для реализации методы
Необязательные для реализации методы
Дополнительные свойства, влияющие на логику работы класса:
При необходимости, вы можете перегрузить стандартные методы API собственной логикой с помощью механизмов ООП. Например:
Теоретически, мы всегда можем выбрать в качестве родителя ExternalApi::Model::AbstractMethods::AbstractMethod, и самостоятельно реализовать всю логику проверки входящих данных и выборки новостей. Это выглядело бы примерно так:
Но мы выберем более простой путь и воспользуемся готовым базовым классом, который уже все это делает за нас. Так как наш метод news.getList должен возвращать список новостей для авторизованных пользователей, наиболее подходящий родительский класс для нас является ExternalApi::Model::AbstractMethods::AbstractGetList.
Создадим файл в нашем модуле согласно указанной выше маске /modules/modulename/model/externalapi/news/getlist.inc.php со следующим содержанием:
Таким образом мы создали самый простейший метод API, для которого будет сформирована автоматическая справка. Данный метод невозможно будет вызвать, пока разрешение на его вызов не будет прописано в классе Приложения. Об этом будет сказано ниже. Пока сосредоточимся на некоторых мелочах именно классов методов API.
Метод process вашего класса API должен возвращать массив с корневой секцией response. Это будет являться признаком успешного выполнения запроса. Пример:
В ответе на API запрос эти данные будут преобразованы в JSON.
Наиболее частой задачей для API является возврат некоторого ORM Объекта или целого списка ORM объектов. В ReadyScript имеются готовые методы для подготовки данных к возврату через API.
У каждого ORM объекта, при описании полей можно указать через флаг "appVisible" - видимость данного поля для внешних API. Если данный флаг не указан, то за видимость отвечает флаг visible, который по умолчанию равен true.
Пример:
Для получения значений полей ORM объекта в виде массива с учетом видимости поля в API, воспользуйтесь вспомогательными функциями:
Пример 1:
Пример 2:
В случае, если во время выполнения запроса возникла ошибка, её необходимо отобразить пользователю в ответ на запрос к API. Для этого достаточно бросить исключение. Все исключения, потомки ExternalApi::Model::AbstractException, будут возвращены пользователю в ответе на запрос API в требуемом формате(JSON). При возникновении ошибки, ответ в формате JSON выглядит так:
Модуль ExternalApi предлагает класс с базовым набором исключений ExternalApi::Model::Exception.
Класс исключений ExternalApi::Model::AbstractException имеет измененный конструктор, который в аргументе code_string принимает строковый идентификатор исключения, в отличие от стандартного класса исключения, где код должен быть числовым. Это необходимо, чтобы снизить вероятность конфликтов идентификаторов ошибок, так как любой модуль может привносить собственные коды ошибок.
Конструктор исключения:
Где:
Если в процессе работы вашего метода API происходит ошибка, которая не присутствует в классе ExternalApi::Model::Exception, вы можете зарегистрировать собственный класс исключений с необходимыми ошибками с помощью обработки события externalapi.getexceptions.
Рассмотрим пример регистрации собственного класса и вызова исключения в процессе выполнения метода API. Модуль "Внешнее API" автоматически разбирает комментарии к константам, заданным в классе исключения, используя эти данные в качестве пояснения в справке к API. Названия констант с идентификаторами ошибок должны начинаться с префикса ERROR_.
Создадим собственный класс исключения в файле /modules/modulename/model/externalapiexception.inc.php
Зарегистрируем класс исключений для отображения в справке с помощью обработки события в файле /modules/modulename/config/handlers.inc.php
Бросим исключение при выполнении метода API.
Пользователь получит следующие JSON данные:
Модуль "Внешнее API" поддерживает возможность версионности методов API. Это означает, что метод различных версии может иметь различный набор параметров, а также возвращать различный результат.
Пример вызова метода news.getList версии 1 /api/methods/news.getList?token=abcd...&v=1
Пример вызова метода news.getList версии 2 /api/methods/news.getList?token=abcd...&some_param=345&v=2
Рассмотрим подробнее, как создать несколько версий одного метода API. Версия API передается в запросе к методу через необязтальный параметр v. Если параметр v не передан, то используется версия по умолчанию (задается в настройках модуля). Модуль "Внешнее API" сперва пытается найти метод по маске processVerX, где X - номер версии. Если метода с таким именем в классе нет, то X понижается до предыдущей версии и происходит повторный поиск функции processVerX процесс повторяется до тех пор, пока цикл не дойдет до версии 1, что означает что будет вызван метод по умолчанию process.
Что дает такой подход? Рассмотрим на примере. Часто бывает, что в API только часть функций будет иметь отличную реализацию версии 2 и 3, остальные методы API должны возвращать одинаковый результат как в версии 3, так и 2, так и в версии 1. Рассмотрим детально работу системы версий на примере кода трех различных методов API.
Метод API news.getList 3х версий
Метод API order.get, имеющий реализацию только версии 1 и 2
Метод API order.sellStatistic, имеющий реализацию только версии 1
В комментариях видно в каком случае какие методы будут вызваны при обращении к API. Логика вызова ближайшей предыдущей версии очень удобна на практике, так как если вы обновили до третьей версии некоторые методы API, стороннее приложение может подставлять ?v=3 ко всем запросам к API и это не будет вызывать ошибку. Если какой-то метод будет иметь версию 3 будет вызван он, если у метода будет реализация только версии 2, то будет вызван он, во всех остальных случаях будет вызван метод по умолчанию, имеющий версию 1.
В справке /api/help, напротив каждого метода будет видно, какие версии он поддерживает. Эта информация автоматически собирается модулем "Внешнее API" с помощью Reflection.
Язык, на котором следует вернуть результат передается через необязательный параметр lang (по умлчанию он равен ru). В случае, если параметр lang передан, перед выполнением метода API, модуль устанвливает указанный язык в качестве текущего с помощью системного метода RS::Language::Core::setSystemLang.
На странице справки по методам API (/api/help), параметр lang устанавливает язык, на котором будет отображена справка. Модуль "Внешнее API" автоматически парсит PHPDoc комментарии к методам process и формирует справку по каждому аргументу, а также по секциям:
Модуль внешнее API может автоматически формировать справку на нескольких языках, если использовать специальный синтаксис при создании phpDoc комментария. Рассмотрим подробнее пример.
Фраза #lang-[двухсимвольный идентификатор языка]: задает начало описания на указанном языке. С помощью данной фразы можно создавать описание для нескольких языков. По умолчанию используется русский язык. Как только вы создадите описание на новом языке, оно тут же появится на странице справки API в секции переключения языков.
Модуль "Внешнее API" использует возможности PHP Refrection, чтобы определить какие параметры ожидает метод API. Имена переменных читаются из аргументов функции process, тип переменных читается из PHPDoc комментариев. Пример:
ReadyScript автоматически найдет параметры token и order_id, filter в суперглобальных массивах POST, GET, FILES приведет их к типам string, integer, array соответственно. Строковые типы будут пропущены через функцию экранирования. Строковые значения в массивах будут также рекурсивно пропущены через функцию экранирования. Подготовленные данные поступят на вход к методу API в параметре $params.
Часто требуется принимать сложную структуру данных в одном из параметров метода API, например, если дело касается запросов на обновление данных. В этом случае рекомендуется использовать массив с некой структурой вложенных секций.
Например, предположим, у нас должен быть метод order.update, который должен ожидать параметры:
Так как на вход должен поступать сложный массив, необходимо его тщательно валидировать, точно подсказывать о наличии ошибок в нужном узле массива. ReadyScript предлагает готовый инструмент для валидации вложенной структуры массивов. Рассмотрим его подробнее.
Для валидации массивов предназначен класс ExternalApi::Model::Validator::ValidateArray. Класс имеет следующие следующие публичные методы:
Рассмотрим пример схемы валидации массива $schema:
Валидатор принимает ключи, начинающиеся с @ за технические инструкции. В настоящее время поддерживаются следующие ключи:
Пример использования функций валидации в методе API.
Модуль "Внешнее API" строит автоматическую документацию на основе PHPDoc комментариев функции process в методах API. Для построения качественной документации обязательно включать в описание функции следующие секции:
Пример хорошо документированного метода:
Для описанного выше метода будет сформирована следующая документация:
Получить авторизационный токен (соответственно пользоваться методами API, требующими токен) можно только для определенного приложения. ID приложения передается в параметре client_id в запросе на авторизацию.
Приложением называется зарегистрированный с помощью события getapps класс, потомок от RS::RemoteApp::AbstractAppType. Приложением может являться "Desktop приложение для уведомлений", "Мобильное приложение Интернет-магазин", "Мобильное приложение для администраторов", иными словами любой программный продукт, требующий подключения извне к вашему магазину, должен быть оформлен в виде специального класса в ReadyScript. Если приложение должно иметь доступ к вншним API, его класс должен имплементировать интерфейс ExternalApi::Model::App::InterfaceHasApi. Рассмотрим интерфейс подробнее.
Для упрощения разработки, мы создали абстрактный класс ExternalApi::Model::App::AbstractAppType, который можно использовать в качестве базового для приложений, требующих доступ к API.
Теперь рассмотрим пример регистрации в системе приложения, которое будет получать доступ к API news.getList из которого будет осуществляться авторизация. Сперва создадим класс нашего вымышленного приложения по отображению новостей.
Зарегистрируем наш класс приложения с помощью обработки события getapps в файле handlers.inc.php.
После регистрации приложения, его client_id можно использовать в методе авторизации oauth.token, выданный токен будет иметь права на обращение к методу news.getList.
Приложение может иметь доступ к различным методам API с различными уровнями доступа. Рассмотрим более сложный пример реализации метода getAppRights класса некоторого абстрактного приложения "StoreManagement".
Предположим, что приложение предназначено для курьера и для администратора. В случае, если пользователь, авторизовавшийся в приложении состоит в группе курьеров, то API должно отдавать только предназначенные для него заказы, а если авторизовавшийся пользователь администратор, то API должны отдавать все заказы.
Как это реализовать? С помощью метода getToken() в классе приложения мы можем получить объект авторизационного токены, из которго мы можем получить пользователя, у которого мы можем проверить группы, в которых он состоит. В зависимости от группы, метод getAppRights может возвращать различные права доступа к API. Главное, чтобы сам метод API имел поддержку различной выдачи в зависимости от прав пользователя, реализованную в методе process.
Пример сложной реализации метода getAppRights.
Далее в методе API можно реализовать логику проверки прав
Модуль "Внешнее API" привносит в систему следующие события:
Идентификатор события | Правила формирования идентификатора | Тип параметра | Когда происходит |
---|---|---|---|
externalapi.getexceptions | - | array of ExternalApi::Model::AbstractException. Массив классов исключений | Вызывается во время рендеринга справочной страницы по API |
api.МЕТОД.success | МЕТОД - полный идентификатор метода API. Например: api.order.get.success или api.order.getlist.success. Все знаки обязательно в нижнем регистре. | array. Элементы:
| Вызывается после выполнения метода API. Параметр result может быть изменен, это повлияет на результат выполнения API. |
ReadyScript предлагает способ однофакторной авторизации через API метод oauth.token, входящий в стандарт OAuth 2.0 (https://tools.ietf.org/html/draft-ietf-oauth-v2-13#section-4.3) Метод позволяет получать авторизационный токен, который наделен правами, необходимыми для приложения client_id.
Метод обрабатывает только POST запрос со следующими параметрами:
Пример запроса:
В случае успешной авторизации, метод вернет следующий результат:
Описание полей результата запроса.
Разбор часто возникающих ошибок:
После успешной регистрации, модуль Внешнее API создает в базе данных запись, которая содержит авторизационный токен, ID пользователя, ID приложения, запросившего токен, время протухания токена, дату создания, а также другие сведения.
Время жизни токена присваивается при создании токена на основе настроек модуля "Внешнее API".
Как и для всех записей в базе, ReadyScript предлагает ORM объект для авторизационного токена ExternalApi::Model::Orm::AuthorizationToken. Используйте объект авторизационного токена в ваших методах API, через свойство $this->token, чтобы получить id пользователя ($this->token->getUser()->id), обратившегося к API.
Для удобства разработки, все авторизационные токены можно просмотреть в админстративной панел в разделе Веб-сайт → Настройка модулей → Внешнее API нажав на ссылку "Авторизационные токены".
В случае, если необходимо реализовать в приложении авторизацию, согласно выставленным настройкам ReadyScript (включая двухфакторную авторизацию), то необходимо использовать универсальный метод авторизации oauth.login.
Метод обрабатывает только POST запрос со следующими параметрами:
Если в интернет-магазине включена однофакторная авторизация, или второй фактор недавно подтверждался (верификационная сессия имеет флаг успешного ввода кода), то данный метод будет работать также как oauth.login и возвращать авторизационный токен и сведения о пользователе.
Пример запроса:
В случае успешной авторизации, метод вернет результат, аналогичный oauth.token:
Если в интернет-магазине включена двухфакторная авторизация, то данный метод будет возвращать сведения о верификационной сессии. Далее будет необходимо с помощью метода verification.checkCode завершить авторизацию.
Рассмотрим процесс двухфакторной авторизации:
Далее выполняем запрос на ввод кода авторизации:
В случае успеха метод вернет результат, аналогичный oauth.token:
В случае ошибочного верификационного кода, возвращаются сведения о верификационной сессии с заполненным полем response.verification.session.error
Если в настройках модуля "Внешнее API" включена опция "Включить логирование запросов", то система будет созранять все запросы и ответы, связанные с API. Просмотреть каждый запрос можно в административной панели в разделе Веб-сайт → Настройка модулей → Внешнее API нажав на ссылку "Журнал запросов к API".