План перехода на новые-кленовые события от Директории¶
Преамбула¶
Сейчас формат событий от директории чересчур запутан, местами избыточен и неинтуитивен. Когда мы их проектировали, то перемудрили и теперь вынуждены признать, что это место требует переделки. Вот лишь некоторые из проблем:
Формат разных событий, хотя и похож, но тем не менее иногда сильно отличается и обманывает ожидания.
Наличие опции expand_content усложняет понимание того, каких данных ожидать в payload.
В коде Директории генерация одного и того же типа событий может происходить в разных местах, но из-за того, что почти всегда это делается через обобщённую функцию, иногда возникает ситуация, что данные для события складываются в базу и payload в чуть разном состоянии. Из-за этого, payload одного и того же события может отличаться.
Далее изложен план по переделке формата событий и переходу со старого формата на новый.
Что нужно сделать¶
Основные вещи которые нужно сделать:
поменять формат событий на более интуитивный и понятный;
сделать код для генерации событий более защищённым от ошибок;
позволить клиентам API постепенно мигрировать со старого формата на новый.
Изменение формата¶
Текущий формат обусловлен тем, что мы пытались сделать унификацию разных типов событий. Отсюда и получилось что данные выглядят примерно так:
{
"content": {
"diff": {
"contacts": [
[
{
"type": "skype",
"value": "the-bob"
},
{
"type": "email",
"value": "bob@home.com"
}
],
[
{
"type": "skype",
"value": "the-bob"
}
]
],
"position": [
{
"ru": "Тестировщик"
},
{
"ru": "Разработчик"
}
]
},
"directly": true
},
"event": "user_property_changed",
"obj": {
"about": null,
"aliases": [],
"birthday": null,
"contacts": [
{
"type": "skype",
"value": "the-bob"
}
],
"department_id": 2,
"email": "bob@art-dev.yaconnect.com",
"external_id": null,
"gender": "male",
"groups": [],
"id": 100500,
"is_admin": false,
"is_dismissed": false,
"login": "bob",
"name": {
"first_name": {
"ru": "Bob"
},
"last_name": {
"ru": "Hopkins"
}
},
"nickname": "bob",
"position": {
"ru": "Разработчик"
}
},
"org_id": 12,
"revision": 1444
}
Это пример события user_property_changed
Тут мы видим два поля с данными - obj
и content
. Почему obj
не находится в content
,
но в там есть diff
- не понятно.
Вот другой пример, событие department_user_deleted
:
{
"content": {
"diff": {
"members": {
"add": {},
"remove": {
"users": [
100500
]
}
}
},
"directly": true,
"subject": {
"about": null,
"aliases": [],
"birthday": null,
"contacts": [
{
"type": "skype",
"value": "the-bob"
}
],
"department_id": 2,
"email": "bob@example.com",
"external_id": null,
"gender": "male",
"groups": [],
"id": 100500,
"is_dismissed": false,
"login": null,
"name": {
"first_name": {
"ru": "Bob"
},
"last_name": {
"ru": "Hopkins"
}
},
"nickname": "bob",
"org_id": 12,
"position": {
"ru": "Разработчик"
}
}
},
"event": "department_user_deleted",
"obj": {
"description": {
"ru": ""
},
"email": null,
"external_id": null,
"id": 1,
"label": null,
"members_count": 3,
"name": {
"en": "All employees",
"ru": "Все сотрудники"
},
"parent_id": null,
"removed": false
},
"org_id": 12,
"revision": 1444
}
Тут в словаре content
появляются ещё два поля: subject
и direct
.
При этом в subject
полностью описание сотрудника, которого удалили из
отдела, а в direct
- признак того, что пользователь входил непосредственно
в тот отдел, который указан в поле obj
.
Как видно, всё очень сложно. Поэтому предлагается формат событий упростить, сделать более лаконичным и привязанным к конкретному типу событий.
К примеру, вышеупомянутый user_property_changed
будет выглядеть как-то так:
{
"org_id": 12,
"revision": 1444
"event": "user_property_changed",
"user_id": 100500,
"diff": {
"contacts": {
"removed": [
{
"type": "email",
"value": "bob@home.com"
}
],
},
"position": {
"before": "Тестировщик",
"after": "Разработчик"
]
}
}
При этом поля org_id
, revision
и event
- обязательные, а остальные опциональные.
А вот так будет выглядеть событие department_user_deleted
:
{
"event": "department_user_deleted",
"org_id": 12,
"revision": 1444
"user_id": 100500,
"departement_id": 1,
"directly": true,
}
Ну разве не прелесть!?
٩(◕‿◕)۶
Так как же добиться этой прелести и начать её использовать?¶
В коде Директории придётся какое-то время поддерживать оба формата. Для этого, нужно ввести версионирование, такое же, как и для остальной части API. Подписки на события, события в базе и ручки для получения событий, должны быть версионированы.
Код, генерирующий события, придётся дублировать, создавая одновременно события старого, и нового образца.
Предлагается в коде генерировать события с помощью одной функции
generate_event
, которая будет принимать название события, и kwargs,
затем строить словарь, соответствующий payload события и проверять его
на соответствие заданной json схеме. Сами JSON схемы каждого из событий,
будут частью API и доступны, как часть документации.
Переход¶
Переходить на новый формат событий можно будет постепенно. Для перехода надо будет сделать несколько вещей:
На время поддержать обработку и старого и нового формата payload, опираясь на версию API, передаваемую в заголовке X-API-Version.
Одномоментно подписаться на новую версию событий и отписаться от старой.
Если есть код, использующий ручку
/events/
, то перейти там на использование новой версии API.
И это можно делать поэтапно - сначала для одного типа событий, затем для другого, и так далее.