96 lines
7.9 KiB
Markdown
96 lines
7.9 KiB
Markdown
# Эндпоинты сервиса mapper
|
||
|
||
Документ описывает HTTP-интерфейс сервиса `mapper` (flows mapper): собственные эндпоинты, которые сервис публикует, и внешние эндпоинты сервисов Sarex, к которым он обращается для сборки ответа.
|
||
|
||
## Как устроено взаимодействие
|
||
|
||
`mapper` — асинхронный FastAPI-прокси-агрегатор. Каждый входящий запрос:
|
||
|
||
1. проходит аутентификацию (`app/dependensies.py:get_user_data`) — из заголовков `Authorization` и опционального `Identity` извлекается `user_id` (подпись JWT не проверяется);
|
||
2. создаёт httpx-клиенты к нужным внешним сервисам (`app/config.py`, базовые хосты — из `*_HOST`, `verify=False`, заголовки авторизации пробрасываются);
|
||
3. параллельно-последовательно запрашивает 2 внешних сервиса через `ServiceManager.get_response()` (`app/utils.py`);
|
||
4. при `REDIS_USE=True` кеширует успешные (200) ответы в Redis по ключу `"{user_id}_{url}"`, а при ошибке апстрима возвращает данные из кеша;
|
||
5. объединяет ответы (`modify_pdm_data` / `modify_notes_data`) и отдаёт результат.
|
||
|
||
Если любой из двух апстримов вернул `None` (ошибка и нет кеша) — роутер отвечает `400 Bad Request`.
|
||
|
||
## Собственные эндпоинты (что публикует mapper)
|
||
|
||
Базовый префикс — `API_PREFIX` (по умолчанию `/api/v1`). Оба эндпоинта требуют заголовок `Authorization` (и `Identity` для режима Zitadel).
|
||
|
||
| Метод | Путь | Назначение | Ответ |
|
||
| --- | --- | --- | --- |
|
||
| GET | `/api/v1/disks/{disk}/documents/` | Документы диска, обогащённые review-данными из сервиса процессов | `object` (`{"documents": [...]}`) |
|
||
| GET | `/api/v1/notes/{service}/{entity}/{instance_id}/` | Заметки сущности, обогащённые target-links из Django-бэкенда | `array` (список заметок) |
|
||
|
||
### `GET /api/v1/disks/{disk}/documents/`
|
||
|
||
Параметры пути: `disk` (string).
|
||
|
||
Логика (`routers.py:get_documents`):
|
||
|
||
- запрос к **documentations**: `GET /disks/{disk}/documents` → берётся поле `documents`;
|
||
- запрос к **flows**: `GET /documents/?full=true`;
|
||
- `modify_pdm_data` матчит по `document_id`/`bundle_id` и добавляет `review_data` в соответствующие бандлы документов.
|
||
|
||
### `GET /api/v1/notes/{service}/{entity}/{instance_id}/`
|
||
|
||
Параметры пути: `service`, `entity`, `instance_id` (string). Дополнительно **все query-параметры запроса пробрасываются** в сервис заметок (к ним добавляется `full=true`).
|
||
|
||
Логика (`routers.py:get_notes`):
|
||
|
||
- запрос к **notes**: `GET /notes/{service}/{entity}/{instance_id}/?full=true&<проброшенные query>`;
|
||
- запрос к **Django**: `GET /core/target-links/` (полный путь — `{DJANGO_HOST}/core/target-links/`);
|
||
- `modify_notes_data` заменяет id-ссылки в поле `links` каждой заметки на объекты target-links.
|
||
|
||
Полное описание схем — в `openapi.yaml`.
|
||
|
||
## Внешние сервисы и базовые хосты по окружениям
|
||
|
||
Базовые хосты берутся из `*_HOST` (`app/config.py`). Итоговый URL = `<HOST>` + путь ниже. Значения по окружениям — из `.helm/values.yaml` (деплой из репозитория сервиса) и overlay'ов инфра-репозитория.
|
||
|
||
| Сервис | Переменная | Дефолт в коде (stage) | preprod | production | brusnika-stage | brusnika-prod |
|
||
| --- | --- | --- | --- | --- | --- | --- |
|
||
| documentations | `DOCUMENTATION_HOST` | `https://stage-api.sarex.io/documentations/api/v1` | `https://api.preprod.sarex.io/documentations/api/v1` | `https://api.sarex.io/documentations/api/v1` | `https://test.sarex.brusnika.tech/documentations/api/v1` | `https://cde.brusnika.ru/documentations/api/v1` |
|
||
| flows | `FLOW_HOST` | `https://stage-api.sarex.io/flows/api/v1` | `https://api.preprod.sarex.io/flows/api/v1` | `https://api.sarex.io/flows/api/v1` | `https://test.sarex.brusnika.tech/flows/api/v1` | `https://cde.brusnika.ru/flows/api/v1` |
|
||
| django (sarex-backend) | `DJANGO_HOST` | `https://stage.sarex.io/api` | `https://preprod.sarex.io/api` | `https://lk.sarex.io/api` | `https://test.sarex.brusnika.tech/api` | `https://cde.brusnika.ru/api` |
|
||
| notes | `NOTE_HOST` | `https://stage-api.sarex.io/notes/api/v1` | `https://api.preprod.sarex.io/notes/api/v1` | `https://api.sarex.io/notes/api/v1` | `https://test.sarex.brusnika.tech/notes/api/v1` | `https://cde.brusnika.ru/notes/api/v1` |
|
||
|
||
## Эндпоинты внешних сервисов (что вызывает mapper)
|
||
|
||
### `documentations`
|
||
|
||
| Метод | Путь | Параметры | Назначение | Где используется |
|
||
| --- | --- | --- | --- | --- |
|
||
| GET | `/disks/{disk}/documents` | `disk` (path) | Документы диска (поле `documents` в ответе) | `get_documents` |
|
||
|
||
### `flows`
|
||
|
||
| Метод | Путь | Параметры | Назначение | Где используется |
|
||
| --- | --- | --- | --- | --- |
|
||
| GET | `/documents/` | `full=true` (query) | Документы процессов с review-данными | `get_documents` |
|
||
|
||
### `notes`
|
||
|
||
| Метод | Путь | Параметры | Назначение | Где используется |
|
||
| --- | --- | --- | --- | --- |
|
||
| GET | `/notes/{service}/{entity}/{instance_id}/` | `service`, `entity`, `instance_id` (path); `full=true` + проброшенные query | Заметки сущности | `get_notes` |
|
||
|
||
### `django` (sarex-backend)
|
||
|
||
| Метод | Путь | Параметры | Назначение | Где используется |
|
||
| --- | --- | --- | --- | --- |
|
||
| GET | `/core/target-links/` | — | Связи (target-links); из ответа берётся `results`, если ответ — объект | `get_notes` |
|
||
|
||
## Заголовки и аутентификация
|
||
|
||
- `Authorization: <token>` — обязателен для обоих эндпоинтов; пробрасывается во все внешние запросы как есть.
|
||
- `Identity: <token>` — опционален; при наличии включается режим Zitadel, заголовок также пробрасывается во внешние запросы.
|
||
- Ответы при ошибках: `401 Unauthorized` (нет `Authorization`), `400 Bad Request` (ошибка апстрима без кеша), `422 Unprocessable Entity` (ошибка валидации параметров пути, стандартный ответ FastAPI).
|
||
|
||
## Замечания
|
||
|
||
- В коде клиент к сервису заметок называется `NoteSettings`/`note`, к Django — `DjangoSettings`/`django`. Пути `/documents/` (flows) и `/notes/.../` (notes) содержат завершающий слэш — важно для совпадения с маршрутами апстрима.
|
||
- Кеш ключуется по `user_id` + URL, поэтому проброшенные query-параметры в `get_notes` не входят в ключ кеша (URL берётся без query). При включённом Redis это стоит учитывать.
|
||
- Healthcheck-эндпоинта у сервиса нет.
|