API v1 и OpenAPI
> Кратко. API v1 — адреса, которыми пользуется само веб-приложение. Вход — токен Bearer из POST /api/v1/auth/login, описание всех адресов — /openapi.json и страница /docs. Адреса v1 меняются вместе с вебом; для внешних систем есть стабильный API v2.
Описание адресов
| Адрес | Что |
|---|---|
/openapi.json |
OpenAPI 3.1 всего API: на копии Алматы 510 адресов, 573 операции |
/docs |
Swagger UI — можно выполнить запрос прямо со страницы («Authorize» — вставить токен) |
/redoc |
то же в виде справочника |
/api/v2/openapi.json |
только адреса v2 — по нему генерируют клиент |
Адреса сгруппированы тегами по разделам (auth, ogc-features, arcgis, api-v2, telemetry …). /mcp
в описании нет: это не REST, а JSON-RPC (см. MCP для разработчиков клиентов). Заголовок описания пока
стандартный («FastAPI», версия 0.1.0).
Вход
API=https://<сервер>/tgid/almaty/map-api # или http://127.0.0.1:<порт> на стенде
TOKEN=$(curl -s -X POST "$API/api/v1/auth/login" -H "Content-Type: application/json" \
-d '{"username":"ivanov.test","password":"<пароль>"}' | jq -r .access_token)
curl -s "$API/api/v1/auth/me" -H "Authorization: Bearer $TOKEN"
Ответ входа: {"access_token": "…", "token_type": "bearer", "role": "viewer", "username": "ivanov.test"}.
Токен — JWT, живёт JWT_EXPIRE_MINUTES минут (по умолчанию 480 — 8 часов), права — пользователя.
GET /api/v1/auth/me — роль, права и город. Заблокированный пользователь теряет доступ сразу: API сверяет
состояние учётной записи на каждом запросе (с коротким кешем).
GET /api/v1/auth/config — без входа: как настроен сервер. На стенде документации (копия Алматы):
{"auth_disabled":true,"auth_required_get":false,"dev_login_enabled":true,"strict_auth":false,
"mutations_enabled":true,"topology_mutations_enabled":true,"city":"almaty","city_label":"Алматы","ai_enabled":true}
При AUTH_DISABLED=true (только стенды) каждый запрос выполняется от имени пользователя dev со всеми правами,
а вход выдаёт токен на любой логин. При DEV_LOGIN_ENABLED=true вход тоже не проверяет пароль. На сервере
с доступом извне оба флага выключены, а STRICT_AUTH=true не даёт API запуститься с ними.
Кроме токена входа есть ключи с назначением: ключ API v2 (scope: api), ключ ArcGIS (arcgis), токен
ИИ-клиента (mcp). Каждый действует только на своих адресах; на адресах v1 ответ — 401 «Токен с ограниченным
назначением … действует только на своих адресах».
Город в адресе
У API нескольких городов город задаётся префиксом пути: /city/astana/api/v1/.... За nginx адрес города —
https://<сервер>/tgid/<город>/map-api/…, префикс nginx подставляет сам. Без префикса отвечают только
/health, /metrics и /auth/check; неизвестный город — 404. API одного города (DB_NAME без
TGID_CITY_DBS) префикс не принимает. Ссылки в ответах OGC и v2 строятся от адреса запроса; за nginx путь
публикации задаёт API_PUBLIC_PREFIX (например /tgid/{city}/map-api).
Постраничная выдача
Единого правила в v1 нет — у каждого семейства адресов своё:
| Где | Параметры | Ответ |
|---|---|---|
журналы (/api/defects, /api/repairs …) и реестры оборудования |
page, page_size (до 200; журнал действий — до 500), search |
{"items", "total", "page", "page_size", "pages"} |
наряды /api/v1/work-orders |
фильтры | {"items", "counts", "overdue"} |
фрагменты /fragments |
— | {"data": [{"id", "name"}]} |
OGC /api/ogc/collections/{id}/items |
limit (до 10 000), offset, ссылка next |
GeoJSON |
FeatureServer …/query |
resultOffset, resultRecordCount (до 2000), exceededTransferLimit |
Esri JSON |
| API v2 | after_id, limit (до 500) |
{"data", "next_after_id"} |
Слишком большой limit — 422 с указанием границы.
Ошибки
{"detail": "текст"}, для правок сети — {"detail": {"code": "…", "message": "…"}}, для неверных полей —
список ошибок pydantic. Язык текста — по Accept-Language. Подробно — в Устройство кода.
curl -s "$API/api/v2/defects/999999999" -H "Accept-Language: en"
# 404 {"detail":"Defect 999999999 not found"}
Долгие операции
Расчёт, выгрузка большого Excel, запекание тайлов идут в очереди Celery. Ответ запуска — {"task_id": "…"},
ход — GET /api/v1/task/{task_id}: status (PENDING, PROGRESS, SUCCESS, FAILURE), в ходе — meta
с сообщением, в конце — result или error. У API нескольких городов задача чужого города — 404.
Для разработчика
- Новый маршрут — в свой файл
routers/, запрос к базе — вdatabase/; зависимость прав —require_permission(...)илиrequire_roles(...), запись —require_mutations_enabled. Если маршрут отдаёт данные сети, у него должна быть своя проверка входа: шлюзAUTH_REQUIRED_GETна стенде обычно выключен. - Веб: новый метод клиента — в свой раздел
services/api/, ошибки —ApiErrorизservices/api/http.ts(status,detail,userMessage). - Тесты маршрутов —
tests/в API: pytest и FastAPITestClientс подменой зависимостей (образец —tests/test_mcp.py,tests/test_webhooks.py). Подробно — Тесты и стенды.
