# Эндпоинты сервиса 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 = `` + путь ниже. Значения по окружениям — из `.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: ` — обязателен для обоих эндпоинтов; пробрасывается во все внешние запросы как есть. - `Identity: ` — опционален; при наличии включается режим 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-эндпоинта у сервиса нет.