diff --git a/docs/integration/api-cheatsheet.md b/docs/integration/api-cheatsheet.md index f706efc..ccad079 100644 --- a/docs/integration/api-cheatsheet.md +++ b/docs/integration/api-cheatsheet.md @@ -2,7 +2,9 @@ Одностраничный референс. Полный гайд — `api-quickstart.md`. -**Base:** `https://ordinis.k8s.264.nstart.cloud/api/v1` · **Version:** `v2.36.0` · **OpenAPI:** `/swagger-ui/index.html` +**Base prod:** `https://ordinis.nstart.cloud/api/v1` (public LE-cert) +**Base staging:** `https://ordinis.k8s.265.nstart.cloud/api/v1` (Swagger UI здесь) +**Version:** `v2.37.x` · **OpenAPI:** `/v3/api-docs` (только staging — на prod Swagger выключен) ## Auth @@ -29,34 +31,43 @@ Scopes: `PUBLIC` (anon ok) · `INTERNAL` (auth) · `RESTRICTED` (admin). | `GET` | `/dictionaries/{name}/dependents` | Кто ссылается на этот dict | | `GET` | `/dictionaries/{name}/changelog` | Список изменений схемы | | `GET` | `/dictionaries/{name}/changelog/{id}/diff` | Diff между версиями | -| `GET` | `/dictionaries/{name}/snapshots?asOf=` | Snapshot на дату (ISO-8601) | -| `GET` | `/{name}/records` | Список записей (⚠️ не `/dictionaries/{name}/records`) | -| `GET` | `/{name}/records/{businessKey}` | Одна запись | -| `GET` | `/{name}/records/{businessKey}/history` | История версий записи | -| `GET` | `/{name}/records/scheduled-summary` | Будущие версии (count + nearestValidFrom) | -| `GET` | `/{name}/records/export.csv` | Bulk export | -| `GET` | `/search?q=&limit=` | Smart search (≥3 chars, trigram) | +| `GET` | `/dictionaries/{name}/snapshots?from=&to=&granularity=` | Bucket'ы изменений для TimeTravel slider (granularity: hour/day/week) | +| `GET` | `/{name}/records?as_scope=PUBLIC` | Список записей (⚠️ **БЕЗ** `/dictionaries/` префикса) | +| `GET` | `/{name}/records/{businessKey}?as_scope=PUBLIC` | Одна запись | +| `GET` | `/dictionaries/{name}/records/{businessKey}/history?as_scope=PUBLIC` | История версий записи (Envers) — **с** `/dictionaries/` | +| `GET` | `/dictionaries/{name}/records/{businessKey}/cascade-preview?as_scope=PUBLIC` | Preview каскада — **с** `/dictionaries/` | +| `GET` | `/{name}/records/scheduled-summary?as_scope=PUBLIC` | Будущие версии (count + nearestValidFrom) | +| `GET` | `/search?q=` | Поиск по справочникам (records не индексируются) | | `GET` | `/ai/info` | `{enabled: bool}` AI feature flag | +> ⚠️ **Корень частой путаницы**: consumer endpoints (`/records/...`) идут БЕЗ `/dictionaries/` префикса. Admin-style audit endpoints (history, cascade-preview, changelog, drafts, snapshots) — С `/dictionaries/`. См. [api-quickstart.md § Topology](api-quickstart.md). + ### Query params (records) ``` -?limit=50&offset=0 pagination -?status=ACTIVE&country=RU фильтр по атрибутам схемы -?scope=INTERNAL если есть права -?asOf=2026-03-15T00:00:00Z bitemporal cut (где поддержано) +?as_scope=PUBLIC,INTERNAL (required) CSV scope filter +?at=2026-03-15T00:00:00Z bitemporal: запись на конкретный момент (validFrom <= at < validTo) +?locale=en-US локаль (или Accept-Language header) +?bbox=lon1,lat1,lon2,lat2 geo: bounding box (для geo-dicts) +?polygon= geo: polygon-фильтр ``` +**Что НЕ работает (на read-api endpoint):** +- `?limit=`, `?offset=` — pagination отсутствует, возвращается весь массив +- `?status=ACTIVE&country=RU` — нет ad-hoc filtering по schema полям; фильтруй на клиенте + ## Write (требует auth) +⚠️ Все write-endpoints — на **writer** сервисе, с `/dictionaries/` префиксом. + | Verb | Path | Что | |---|---|---| -| `POST` | `/{name}/records` | Создать запись (если approval не нужен) | -| `PUT` | `/{name}/records/{businessKey}` | Обновить | -| `DELETE` | `/{name}/records/{businessKey}` | Soft-delete (tombstone) | -| `POST` | `/{name}/records/bulk-close` | Массовое закрытие | -| `POST` | `/{name}/records/{businessKey}/cascade-close` | Закрыть с зависимыми | -| `GET` | `/{name}/records/{businessKey}/cascade-preview` | Preview каскада | +| `POST` | `/dictionaries/{name}/records` | Создать запись (если approval не нужен) | +| `PUT` | `/dictionaries/{name}/records/{businessKey}` | Обновить | +| `DELETE` | `/dictionaries/{name}/records/{businessKey}` | Soft-delete (tombstone) | +| `POST` | `/dictionaries/{name}/records/bulk-close` | Массовое закрытие | +| `POST` | `/dictionaries/{name}/records/{businessKey}/cascade-close` | Закрыть с зависимыми | +| `POST` | `/dictionaries/{name}/records/export-selected.csv` | Bulk export (выборка по ids в body) | | `PATCH` | `/dictionaries/{name}/schema` | Изменить схему inline (non-breaking) | | `PUT` | `/dictionaries/{name}` | Полностью пересоздать (breaking) | @@ -173,16 +184,21 @@ Action types (13): `DICTIONARY_CREATED · SCHEMA_UPDATED · SCHEMA_PUBLISHED · ## 60-second smoke ```bash -ORDINIS=https://ordinis.k8s.264.nstart.cloud +ORDINIS=https://ordinis.nstart.cloud # prod (public LE) +# или: ORDINIS=https://ordinis.k8s.265.nstart.cloud # staging -curl -s $ORDINIS/api/v1/version | jq # alive -curl -s $ORDINIS/api/v1/dictionaries | jq 'length' # >= 40 -curl -s $ORDINIS/api/v1/dictionaries/spacecraft | jq '.scope' # "PUBLIC" -curl -s "$ORDINIS/api/v1/spacecraft/records?limit=1" | jq '.[0].businessKey' -curl -s "$ORDINIS/api/v1/search?q=Sentinel" | jq '.total' # 12 -curl -s $ORDINIS/api/v1/ai/info | jq '.enabled' # true +curl -s $ORDINIS/api/v1/version | jq # alive +curl -s $ORDINIS/api/v1/dictionaries | jq 'length' # 37 на prod / 39 на staging +curl -s $ORDINIS/api/v1/dictionaries/spacecraft | jq '.scope' # "PUBLIC" +curl -s "$ORDINIS/api/v1/spacecraft/records?as_scope=PUBLIC" | jq '.[0].businessKey' +curl -s "$ORDINIS/api/v1/search?q=spacecraft" | jq '.total' # >0 +curl -s $ORDINIS/api/v1/ai/info | jq '.enabled' # true / false ``` +## Postman collection + +Готовая collection с реальными запросами (28 запросов, demo-flow): см. [docs/integration/postman/](postman/) или `~/Desktop/Ordinis-Postman/` (если генерировал локально). + ## Связанные доки `api-quickstart.md` · `bundle-format-spec.md` · `docs/changelog.md` · Swagger UI `/swagger-ui/index.html` diff --git a/docs/integration/api-quickstart.md b/docs/integration/api-quickstart.md index 5b6a2e8..1b33243 100644 --- a/docs/integration/api-quickstart.md +++ b/docs/integration/api-quickstart.md @@ -4,7 +4,7 @@ Practical guide to НСИ-ordinis REST API. Тут не справочник в (для этого есть OpenAPI / Swagger UI), а минимально-достаточный путь от «первый запрос» до «подписался на webhook». -**Версия:** v2.36.0 (`/api/v1`) +**Версия:** v2.37.x (`/api/v1`) **Swagger UI:** `https://ordinis.k8s.265.nstart.cloud/swagger-ui/index.html` (staging — на prod env-flagged) @@ -16,14 +16,15 @@ Practical guide to НСИ-ordinis REST API. Тут не справочник в - Базовый префикс — `/api/v1`. Версионирование URL (breaking changes → `/v2`). - Auth — Keycloak OIDC, Bearer-токен в `Authorization`. Anon разрешён для `PUBLIC` scope. -- Pagination — query-params `?limit=N&offset=M`. По умолчанию `limit=50`. +- Pagination — на records list **не поддерживается**, возвращается весь массив. Для больших dicts фильтруй на клиенте или через `?at=` time-slice. - Ошибки — `application/json` с `{status, code, message, traceId, timestamp}`. ## 1. Base URL и проверка живости ```bash # Production -ORDINIS=https://ordinis.k8s.264.nstart.cloud +ORDINIS=https://ordinis.nstart.cloud # prod (public LE) +# ORDINIS=https://ordinis.k8s.265.nstart.cloud # staging # Staging # ORDINIS=https://ordinis.k8s.265.nstart.cloud @@ -38,7 +39,7 @@ curl "$ORDINIS/api/v1/version" "version": "0.1.0-SNAPSHOT", "commit": "2ca8f053", "branch": "main", - "tag": "v2.36.0", + "tag": "v2.37.0", "builtAt": "2026-05-17T08:18:07.437Z" } ``` @@ -162,9 +163,11 @@ curl "$ORDINIS/api/v1/dictionaries/graph/outgoing" ### 4.1 Список записей ```bash -curl "$ORDINIS/api/v1/spacecraft/records?limit=2" +curl "$ORDINIS/api/v1/spacecraft/records?as_scope=PUBLIC" ``` +`as_scope` обязателен (CSV: `PUBLIC,INTERNAL,RESTRICTED`). + ```json [ { @@ -188,27 +191,34 @@ curl "$ORDINIS/api/v1/spacecraft/records?limit=2" ### 4.2 Одна запись по business key ```bash -curl "$ORDINIS/api/v1/spacecraft/records/1999-068A" +curl "$ORDINIS/api/v1/spacecraft/records/1999-068A?as_scope=PUBLIC" ``` ### 4.3 Фильтры ```bash -# По атрибутам схемы (через query-params) -curl "$ORDINIS/api/v1/spacecraft/records?status=OPERATIONAL&country=RU" +# Locale — для x-localized полей сервер вернёт только указанную локаль +curl "$ORDINIS/api/v1/spacecraft/records/1999-068A?as_scope=PUBLIC&locale=en-US" +# или через стандартный header: +curl -H "Accept-Language: en-US" "$ORDINIS/api/v1/spacecraft/records?as_scope=PUBLIC" -# По scope (если у тебя есть доступ к INTERNAL) +# Time-travel: состояние на конкретный момент (validFrom <= at < validTo) +curl "$ORDINIS/api/v1/spacecraft/records/1999-068A?as_scope=PUBLIC&at=2026-01-01T00:00:00Z" + +# По scope (если есть права на INTERNAL/RESTRICTED) curl -H "Authorization: Bearer $TOKEN" \ - "$ORDINIS/api/v1/spacecraft/records?scope=INTERNAL" + "$ORDINIS/api/v1/spacecraft/records?as_scope=PUBLIC,INTERNAL" -# Pagination -curl "$ORDINIS/api/v1/spacecraft/records?limit=20&offset=40" +# Geo (для geo-dicts с PostGIS support) +curl "$ORDINIS/api/v1/ground_station/records?as_scope=PUBLIC&bbox=30,55,40,60" ``` +⚠️ **НЕ работает на records list endpoint**: `?limit=`, `?offset=` (pagination отсутствует), `?status=...&country=...` (нет ad-hoc filtering по schema полям). Фильтруй на клиенте. + ### 4.4 Сводка по запланированным записям ```bash -curl "$ORDINIS/api/v1/spacecraft/records/scheduled-summary" +curl "$ORDINIS/api/v1/spacecraft/records/scheduled-summary?as_scope=PUBLIC" ``` ```json @@ -267,7 +277,7 @@ curl "$ORDINIS/api/v1/spacecraft/records/1999-068A/history" ### 6.2 Snapshot справочника на дату ```bash -curl "$ORDINIS/api/v1/dictionaries/spacecraft/snapshots?asOf=2026-03-15T00:00:00Z" +curl "$ORDINIS/api/v1/dictionaries/spacecraft/snapshots?from=2026-01-01T00:00:00Z&to=2026-05-01T00:00:00Z&granularity=day" ``` Точная реконструкция справочника на момент `asOf`. Все записи, которые @@ -277,7 +287,7 @@ curl "$ORDINIS/api/v1/dictionaries/spacecraft/snapshots?asOf=2026-03-15T00:00:00 ### 6.3 Changelog схемы (структурные изменения) ```bash -curl "$ORDINIS/api/v1/dictionaries/spacecraft/changelog?limit=10" +curl "$ORDINIS/api/v1/dictionaries/spacecraft/changelog" ``` ```json @@ -503,15 +513,15 @@ curl -X POST -H "Authorization: Bearer $TOKEN" \ ### curl + jq (CI/CD) ```bash -# Все записи активных операторов -curl -s "$ORDINIS/api/v1/operator/records?status=ACTIVE" \ - | jq '.[] | {key: .businessKey, name: .data.name}' +# Все записи операторов в PUBLIC scope; фильтрация на клиенте +curl -s "$ORDINIS/api/v1/operator/records?as_scope=PUBLIC" \ + | jq '.[] | select(.data.status == "ACTIVE") | {key: .businessKey, name: .data.name}' ``` ### TypeScript / Fetch ```ts -const ORDINIS = 'https://ordinis.k8s.264.nstart.cloud' +const ORDINIS = 'https://ordinis.nstart.cloud' type SpacecraftRecord = { businessKey: string @@ -521,9 +531,10 @@ type SpacecraftRecord = { } async function getSpacecraft(): Promise { - const r = await fetch(`${ORDINIS}/api/v1/spacecraft/records?limit=100`, { - headers: { Accept: 'application/json' }, - }) + const r = await fetch( + `${ORDINIS}/api/v1/spacecraft/records?as_scope=PUBLIC`, + { headers: { Accept: 'application/json', 'Accept-Language': 'en-US' } }, + ) if (!r.ok) throw new Error(`Ordinis ${r.status}`) return r.json() } @@ -534,7 +545,7 @@ async function getSpacecraft(): Promise { ```python import requests -ORDINIS = "https://ordinis.k8s.264.nstart.cloud" +ORDINIS = "https://ordinis.nstart.cloud" def smart_search(query: str, limit: int = 10) -> dict: r = requests.get(f"{ORDINIS}/api/v1/search",