Перейти к содержанию

PublicAPI

Важно!

В рамках релиза 3 квартала 2024 года выпущена первая стабильная версия PublicAPI v1.0, в связи с чем поддержка alpha-версии PublicAPI прекращена.

Возможности VK People Hub PublicAPI

VK People Hub PublicAPI - средство для решения задач сервисной интеграции и интеграции с внешними ИС.

Авторизуемый субъект доступа (конечный клиент PublicAPI) - сервис, но не пользователь.

Таким образом:

  • PublicAPI обеспечивает генерализованный доступ к работе с данными безотносительно к субъекту-владельцу (конкретному пользователю, роли, т.п.).
  • Ответственность за порчу данных в системе лежит на субъекте доступа к PublicAPI (сервис-клиент).
    • Рекомендуется регулярное резервное копирование данных.
    • Необходима выдача гранулярных прав доступа конкретного сервиса к конкретному API.
  • Не подходит для осуществления прямого доступа с front-end, но только для вендорских сервисов на стороне back-end.
    • В случае возникновения потребности управления пользовательскими данными с front-end, предлагается использование WidgetSDK на стороне front-end, а также написание собственного сервиса back-end, взаимодействующего с PublicAPI.
    • Не рекомендуется расположение бизнес-логики Вашего сервиса на стороне front-end.

Гарантии обратной совместимости

  • Поддержка устаревшей версии API в течение 2-х квартальных релизов (за исключением alpha-версии PublicAPI, поддержка которой будет прекращена сразу после выхода стабильной версии PublicAPI).
  • Презентация новых версий PublicAPI на ежеквартальных демо продукта VK People Hub.
  • Внесение в документацию сроков вывода устаревших версий API.

Возможности аутентификации и авторизации

Потребители PublicAPI должны проходить аутентификацию и авторизацию для вызова конечных точек. Бизнес-сервис, публикующий конечные точки PublicAPI, производит на своей стороне аутентификацию и авторизацию субъекта доступа с помощью уникального подписанного токена доступа, который характеризует внешнюю систему.

Предполагается, что бизнес-сервис знает про внешнюю систему и её права модели доступов.

Спецификация артефактов:

Название Суть Владелец (Keycloak) Требования к формату Время жизни Ротация (rotation) Отзыв (revocation) Структура Назначение
ESC External System Credentials Application Credentials (Client Credentials) client Client Secret Ручная (через админку Keycloak) Деактивация client client_id + client_secret Характеризует конкретный внешний сервис. Средство получения аутентификационного токена. Вшито в сторонний сервис. НЕ используется в коммуникации с PublicAPI.
ESAT external_system_access_token OAuth Access Token client's service-account Также, как в основном реалме 5 минут Автоматическая (OAuth) Инвалидация session JWT {client_id,scope,...} + signature Характеризует сессию. Средство аутентификации для вызова PublicAPI. Очень короткоживущий артефакт. scope описывает набор микросервисов VK People Hub, к PublicAPI которых может осуществляться доступ с использованием этого токена.
ESRT external_system_refresh_token OAuth Refresh Token client's service-account Также, как в основном реалме 3 дня Автоматическая (OAuth) Инвалидация session Любая произвольная Характеризует сессию. Средство получения нового external_system_access_token. Относительно короткоживущий артефакт.

Получение аутентификационного токена

Внешний сервис осуществляет доступ к VK People Hub PublicAPI с использованием короткоживущего OAuth access_token (external_system_access_token, JWT, предается в заголовке Authorization HTTP запроса).

Последний артефакт внешний сервис получает у IdP в рамках OAuth Client Credentials Flow с использованием долгоживущего артефакта External System Credentials.

Наличие нескольких аутентификационных артефактов повышает безопасность решения (снижаются риски при краже ключей, появляется возможность отзыва и ротации).

Внешний сервис является клиентом ("OAuth Client") по отношению к IdP. Уникальный клиент создаётся на каждый уникальный внешний сервис проектно.

Артефакт External System Credentials на стороне IdP принадлежит сущности клиента ("OAuth Client"); последний, соответственно, характеризует внешний сервис как субъект доступа к PublicBackAPI.

Экземпляр сущности клиента вместе с артефактом External System Credentials генерируется в IdP инженером эксплуатации на этапе первичного развёртывания внешнего сервиса и зашит во внешний сервис:

Инструкция по конфигурированию KeyCloak для создания client для внешнего сервиса и выпуска External System Credentials

Проектная настройка KeyCloak:

  1. Создание Client

  1. Далее в настройках client:

    • Settings:
      • Выключаем функции login и logout.
    • Advanced:
      • Open ID Connect Compatibility Modes:
        • Включаем "Use refresh tokens" и "Use refresh tokens for client credentials grant".
      • Advanced settings:
        • Задаём время жизни access token и refresh token.
    • Client Scopes:
      • Удаляем все scope, созданные по-умолчанию (кроме dedicated).
    • Credentials:
      • Задаём "Client Authenticator" значением "Signed JWT with Client Secret".
    • Keys:
      • Generate new keys → PKCS12
      • Автоматически приватная часть ключа загружается на ПК. Этот артефакт в совокупности с client_id и client_secret и есть External System Credentials.

    Для нового client автоматически создаётся "service account":

    Далее необходимо добавить в Сlient все необходимые Client Scope, чтобы внешний сервис в рамках запроса аутентификационного токена мог запросить доступ к конкретным микросервисам VK People Hub:

    !ВАЖНО: Type обязательно должен быть в каждом случае задан значением "Optional".

Разграничение доступа к PublicBackAPI каждого из микросервисов VK People Hub управляется посредством Client Scopes: для каждого микросервиса существует отдельный "scope".

Имя "scope" соответствует имени микросервиса с приставкой "ph-".

Эта строка константная, она вшивается внутрь кода микросервиса VK People Hub (но не в конфиг/env), и используется микросервисом в рамках логики аутентификации доступа к защищаемым ресурсам.

Внешний сервис при получении external_system_access_token обязан запросить конкретный набор scope:

Стандартная поставка IdP должна содержать в себе заранее созданный набор Client Scopes для каждого микросервиса.

Инструкция по конфигурированию KeyCloak для создания client scopes для микросервисов VK People Hub

Коробочная настройка KeyCloak:

  1. Создание Client Scope

    !ВАЖНО: Принцип задания "name" описан выше.

    !ВАЖНО: Type обязательно должен быть задан значением "Optional".

Виды конечных точек PublicAPI

Конечные точки PublicAPI делятся на типы в зависимости от целевого назначения API:

  • Общего назначения

    • REST-совместимые:
      • URL описывает полный путь к экземпляру бизнес-объекта или классу бизнес-объектов;
      • Поддерживают HTTP-методы GET, POST, PUT, PATCH, DELETE.
    • Обеспечивают работу с единичными экземплярами бизнес-объектов.
    • Ошибки:
      • Статус ответа HTTP (200, 400) соответствует результату работы бизнес-логики.
  • Интеграционные

    • Несовместимы с REST:
      • URL описывает полный путь только к классу бизнес-объектов;
      • В URL в конце обязательно должно быть указано .../batch/ - обозначает пакетную обработку;
      • Поддерживается только HTTP-метод PATCH, при этом конкретная операция над конкретным экземпляром бизнес-объекта задаётся внутри payload запроса (см. подробнее далее);
      • Операция, аналогичная REST-GET не реализуется, вместо этого используются конечные точки общего назначения (см. выше).
    • Обеспечивают пакетную обработку набора экземпляров бизнес-объектов одного типа (diff).
    • Ошибки:
      • Статус ответа HTTP для любой конечной точки (с корректной структурой payload запроса) - 200;
      • Результат работы бизнес-логики над конкретным экземпляром (обработки конкретной операции) задаётся внутри payload ответа.
  • Точки для пакетной загрузки набора бизнес-объектов POST (batch)

    • Точки аналогичны Интеграционным, но:
      • Поддерживается только HTTP-метод POST;
      • Параметр op всегда равен add (op=add) и не указывается в запросе;
      • В структуре элемента указывается только параметр value; id и external_id не используются;
      • Все остальное соответствует правилам и принципам обработки метода PATCH в части валидации, структуры запроса и ответа.

Для всех типов конечных точек в конце URL обязательно наличие прямой косой черты "/" (trailing slash). Исключение: конечные точки, где идентификатором экземпляра бизнес-объекта на конце является имя физического файла (напр., image.png и т.п.).

Описание Интеграционных конечных точек

Интеграционные PublicAPI позволяют произвести загрузку данных пользователей и орг структуры в VK People Hub. Предварительно пользователи должны быть загружены в KeyCloak.

Принципы работы Интеграционных конечных точек:

  1. Ошибка валидации поля не отменяет транзакцию. Статус ответа HTTP для любой конечной точки (с корректной структурой payload запроса) - 200.
  2. Методы обеспечивают пакетную обработку набора экземпляров бизнес-объектов одного типа (diff).
  3. В рамках одной транзакции (одного вызова API) не может быть более одной операции над одним и тем же экземпляром.
  4. Поля в value могут быть опущены (в таком случае им присваивается дефолтное значение при создании ИЛИ их значение не изменяется при replace).

Структура запроса

Структура тела запроса представляет собой JSON массив.

Для операций C/U/D работа производится над вектором (набором) экземпляров бизнес-объекта - в корне задаётся массив из элементов, указывающих операцию и поля бизнес-объекта.

Структура элемента:

Параметр Описание Тип Значения Обязательность Валидация
op Операция, которую следует осуществить над набором или экземпляром бизнес-объекта enum "add" | "replace" | "addreplace" | "remove"
add = добавить строку, присвоить ей внутренний id, записать значения переданных полей, проставить дефолтные значения для остальных полей.
replace = для строки, идентифицированной по id или external_id, заменить значения переданных полей.
addreplace = если идентификатор строки (id или external_id) не передан - поведение операции add. Если передан id - поведение операции replace. Если передан external_id как идентификатор - сначала ищем запись с таким external_id, и если найдена, то заменить переданные поля для нее, если не найдена - то создать новую запись. Если при создании новой записи будет передан external_id и в корне и в value, то при их несовпадении - кидаем ошибку. Однако при замене существующей записи значения external_id в корне и в value могут отличаться, в этом случае мы заменяем external_id для этой записи.
remove = удалить строку, идентифицированную по id или external_id.
да
id Внутреннее id экземпляра бизнес-объекта
Поле, задающее идентификатор поиска экземпляра бизнес-объекта, над которым совершается операция
uuid Зависит от операции, см таблицу Валидация параметров в зависимости от операции "op" Значение должно быть уникальным
external_id или _external_id Внешнее id экземпляра бизнес-объекта, может использоваться с целью мапинга сущности VK People Hub на сущность внешней системы
Поле, задающее идентификатор поиска экземпляра бизнес-объекта, над которым совершается операция
string или null Зависит от операции, см таблицу Валидация параметров в зависимости от операции "op" Значение должно быть уникальным или null
Для экземпляров объектов модели данных с external_id==null, поиск по external_id не осуществляется.
value Содержит список полей набора или экземпляра бизнес-объекта с их значением
не может содержать id внутри себя, но может содержать external_id
JSON object Зависит от операции, см. таблицу Валидация параметров в зависимости от операции "op"

Валидация параметров в зависимости от операции "op"

Операция "op" Параметр
id external_id value Пример
add Должно отсутствовать Должно отсутствовать Обязательное поле
Если не заданы необязательные поля экземпляра бизнес-объекта, то эти поля принимают дефолтные значения: null, 0, пустая строка… - в зависимости от типа данных поля.
Если есть лишнее поле - запрос падает с ошибкой
reason: "Invalid schema. Unknown field {field}"
"op" : "add",
"value" : {
"name" : "Инженер",
"external_id": "4562-b3fc"
}
результат: создается новая запись в БД, ей присваивается внутренний id, поля заполняются указанными значениями
replace Должен быть заполнен строго один из идентификаторов.
Разрешаем искать по external_id и изменять значение external_id у сущности в рамках одной операции.
Если сущность с переданным id не найдена в базе - запрос падает с ошибкой
Обязательное поле
Если не заданы необязательные поля сущности, то эти поля не изменяются
Если есть лишнее поле - запрос падает с ошибкой
reason: "Invalid schema. Unknown field {field}"
"op" : "replace",
"external_id": "4562-b3fc",
"value" : {
"external_id": "1111-1234"
}
Результат: у записи с указанным external_id заменится external_id на указанное значение, другие поля сущности не меняются
addreplace Необязательное поле:
- если идентификатор строки (id или external_id) не передан - поведение операции add.
- если передан id (внутренний) как идентификатор - поведение операции replace.
- если передан external_id как идентификатор - сначала ищем запись с таким external_id, и если найдена, то заменить переданные поля для нее, если не найдена - то - создать новую запись
Обязательное поле
Если есть лишнее поле -запрос падает с ошибкой
reason: "Invalid schema. Unknown field {field}"
"op" : "addreplace",
"external_id": "4562-b3fc",
"value" : {
"external_id": "4562-b3fc",
"name": "Инженер"
}
Результат: у записи с указанным external_id заменится name на переданное значение.

"op" : "addreplace",
"value" : {
"name": "Инженер"
}
Результат: создается новая запись в БД, ей присваивается внутренний id, поле name заполняется указанными значением, external_id проставляется дефолтным значением (пустая строка)
remove Должно быть заполнено строго одно из полей.
Если сущность с переданным id не найдена в базе - запрос падает с ошибкой
должно отсутствовать
Если есть лишнее поле -запрос падает с ошибкой
reason: "Invalid schema. Unknown field {field}"
"op" : "remove",
"external_id": "4562-b3fc"
Результат: удалится запись с указанным external_id

Пример тела запроса:

{
  [
    {
   "op" : "add",
   "value" : {
   "name" : "Инженер",
   "external_id": "1111-1234"
            }
    },
    {
   "op" : "remove",
   "external_id": "4562-b3fc"
    }
  ]
}

Структура ответа

При применении ОР-операции в response отдаем массив с таким же порядком item, в каждом элементе массива указываем ключ-идентификатор и результат обработки (структура response: id, external_id, success (true/false), reason (e.g. Invalid value for "name")).

Параметр Описание Обязательность
details Детали обработки каждой операции Да
Параметры внутри details:
id Внутреннее id экземпляра бизнес-объекта Да
external_id Внешнее id экземпляра бизнес-объекта Да
success Признак успеха выполнения операции над экземпляром бизнес-объекта:
- true - успешное выполнение операции;
- false - неуспешное выполнение операции. Входные параметры не прошли валидацию
Да
reason Описание причины невыполнения операции над экземпляром бизнес-объекта. Указывается только при success=false. При успешном выполнении операции reason=null Да
meta Содержит данные о кол-ве объектов в выгрузке и кол-ве успешных/неуспешных операций Да
Параметры внутри meta:
total_items Количество операций, которые были обработаны Да
total_succeed Количество успешно обработанных операций Да
total_failed Количество неуспешно обработанных операций Да

Пример ответа:

{
  "details": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "external_id": "4562-b3fc",
      "success": true,
      "reason": null
    },
    {
      "id": null,
      "external_id": null,
      "success": false,
      "reason": "Wrong structure for \"add\" operation"
    }
  ],
  "meta": {
    "total_items": 2,
    "total_succeed": 1,
    "total_failed": 1
  }
}

Требования к заголовкам

Ниже представлены допустимые к использованию заголовки HTTP. Использование других заголовков для целей PublicAPI - недопустимо. При отсутствии обязательных заголовков запрос не проходит.

Заголовок запрос По-умолчанию Обязательность Описание
Host - Да -
Authorization - Да Заголовок Authorization используется для передачи external_system_access_token
Accept application/json Нет Этот заголовок указывает, какие типы контента клиент готов принять от сервера
Content-Type application/json Да Заголовок Content-Type сообщает серверу о типе контента, который передается в теле запроса. Обязателен для всех методов.
X-Trace-Id - Нет Указывает идентификатор трейса

Методы PublicAPI

Методы PublicAPI Профили

Методы PublicAPI Оргструктура

Методы PublicAPI Справочники

Методы PublicAPI Внешние уведомления