openapi: 3.0.3 info: title: Mapper Service API version: "1.0.0" description: | REST API сервиса **mapper** (flows mapper) — mini-HTTP-сервис, который объединяет (мапит) данные нескольких сервисов Sarex: документы дисков из сервиса документации (`documentations`) обогащаются review-данными из сервиса процессов (`flows`); заметки из сервиса `notes` обогащаются связями (target-links) из Django-бэкенда. Сервис написан на Python (**FastAPI**), приложение создаётся в `src/app/main.py` (`app = FastAPI()`), маршруты — в `src/app/routers.py` с префиксом `API_PREFIX` (по умолчанию `/api/v1`). ### Аутентификация Оба эндпоинта требуют заголовок `Authorization`. Опциональный заголовок `Identity` включает режим Zitadel. Подпись JWT **не проверяется** (`verify_signature=False`, `src/app/dependensies.py`) — доверие к токену обеспечивается сетевым слоем (Istio/ingress). Из токена извлекается `user_id`, который используется как часть ключа кеша Redis. ### Агрегация и кеш Каждый запрос обращается к двум внешним сервисам через `ServiceManager` (`src/app/utils.py`). При `REDIS_USE=True` успешные (200) ответы апстрима кешируются в Redis (ключ `"{user_id}_{url}"`, TTL `REDIS_EXPIRE_DAYS` суток), а при ошибке апстрима отдаётся кеш. Если хотя бы один апстрим вернул ошибку и кеша нет — сервис отвечает `400 Bad Request`. Схемы ответов заданы как свободные JSON-структуры (`object`/`array`), так как сервис проксирует и объединяет ответы внешних сервисов без фиксированной модели. servers: - url: https://api.sarex.io/mapper description: production (Sarex) - url: https://stage-api.sarex.io/mapper description: stage (Sarex) - url: https://cde.brusnika.ru/mapper description: production (Brusnika) - url: https://test.sarex.brusnika.tech/mapper description: stage (Brusnika) tags: - name: documents description: Документы дисков, обогащённые review-данными процессов - name: notes description: Заметки, обогащённые связями (target-links) paths: /api/v1/disks/{disk}/documents/: get: tags: - documents summary: Документы диска с review-данными operationId: get_documents description: | Возвращает документы диска из сервиса документации, обогащённые review-данными из сервиса процессов. Внутри выполняются запросы `GET {DOCUMENTATION_HOST}/disks/{disk}/documents` и `GET {FLOW_HOST}/documents/?full=true`, после чего review-данные добавляются в поле `review_data` соответствующих бандлов документов (`modify_pdm_data`). security: - bearerAuth: [] parameters: - name: disk in: path required: true description: Идентификатор диска schema: type: string - name: Authorization in: header required: true description: Токен доступа (пробрасывается во внешние сервисы) schema: type: string - name: Identity in: header required: false description: Identity-токен (включает режим Zitadel) schema: type: string responses: "200": description: Успешный ответ content: application/json: schema: $ref: "#/components/schemas/DocumentsResponse" "400": description: Один из внешних сервисов недоступен и данных в кеше нет "401": description: Отсутствует заголовок Authorization "422": $ref: "#/components/responses/ValidationError" /api/v1/notes/{service}/{entity}/{instance_id}/: get: tags: - notes summary: Заметки сущности со связями (target-links) operationId: get_notes description: | Возвращает заметки сущности из сервиса `notes`, у которых поле `links` заменено на объекты связей (target-links) из Django-бэкенда. Внутри выполняются запросы `GET {NOTE_HOST}/notes/{service}/{entity}/{instance_id}/?full=true` (с проброской всех query-параметров запроса) и `GET {DJANGO_HOST}/core/target-links/`, после чего выполняется объединение (`modify_notes_data`). security: - bearerAuth: [] parameters: - name: service in: path required: true description: Логическое имя сервиса-владельца сущности schema: type: string - name: entity in: path required: true description: Тип сущности schema: type: string - name: instance_id in: path required: true description: Идентификатор экземпляра сущности schema: type: string - name: Authorization in: header required: true description: Токен доступа (пробрасывается во внешние сервисы) schema: type: string - name: Identity in: header required: false description: Identity-токен (включает режим Zitadel) schema: type: string responses: "200": description: | Успешный ответ — список заметок. Все дополнительные query-параметры запроса проксируются в сервис заметок. content: application/json: schema: $ref: "#/components/schemas/NotesResponse" "400": description: Один из внешних сервисов недоступен и данных в кеше нет "401": description: Отсутствует заголовок Authorization "422": $ref: "#/components/responses/ValidationError" components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT description: | Токен передаётся заголовком `Authorization`. Подпись не проверяется приложением. Для режима Zitadel дополнительно передаётся заголовок `Identity`. responses: ValidationError: description: Ошибка валидации параметров запроса content: application/json: schema: $ref: "#/components/schemas/HTTPValidationError" schemas: DocumentsResponse: type: object description: | Ответ агрегатора документов. Структура повторяет ответ сервиса документации, где в бандлы добавлено поле `review_data` с данными из сервиса процессов. properties: documents: type: array items: type: object additionalProperties: true additionalProperties: true NotesResponse: type: array description: | Список заметок сервиса `notes`, где поле `links` каждой заметки заменено на объекты связей (target-links). items: type: object additionalProperties: true ValidationErrorItem: type: object properties: loc: type: array items: anyOf: - type: string - type: integer msg: type: string type: type: string required: - loc - msg - type HTTPValidationError: type: object properties: detail: type: array items: $ref: "#/components/schemas/ValidationErrorItem"