wiki: ingest round-2 outcome — openapi-generator gotchas + sched-admin-client-openapi updated (all F-1..F-5 closed, raw_ops deleted)
This commit is contained in:
@@ -8,12 +8,38 @@ updated: 2026-08-18
|
||||
|
||||
# openapi-generator + OpenAPI 3.1 — gotchas
|
||||
|
||||
Проверено вживую на F&F-раунде sched «клиент на любом ЯП одной командой»
|
||||
(2026-08-18): Python-клиент из `@sched/admin-api@0.1.2` спеки (3.1.0, 15 путей)
|
||||
через `openapi-generator` **7.24.0** (`-g python`, pydantic v2). Спеку НЕ чинили
|
||||
(их импл, TDD) — обходили. Находки F-1..F-5 полные — в
|
||||
`sched/.agents/inbox/2026-08-18T19-15-43Z-admin-fnf-openapi-client-report.md`;
|
||||
здесь — переиспользуемая суть.
|
||||
Проверено вживую на F&F-раундах sched «клиент на любом ЯП одной командой»
|
||||
(2026-08-18): Python-клиент из спеки `@sched/admin-api` через
|
||||
`openapi-generator` **7.24.0** (`-g python`, pydantic v2). Спеку НЕ чинили —
|
||||
обходили (round 1, 0.1.2). Round 2 (0.2.0): все гочи 1–4 **закрыты фиксами
|
||||
спеки/сервера**, raw-обход удалён — см. «Статус после round 2» ниже.
|
||||
|
||||
## Статус после round 2 (0.2.0 / daemon 0.3.5)
|
||||
|
||||
Все 5 находок round 1 подтверждены закрытыми (ретест 2026-08-18, отчёт
|
||||
`sched/.agents/inbox/2026-08-18T22-55-00Z-admin-openapi-fixes-round2-retest.md`):
|
||||
|
||||
- **Гоча 1 (wrapped-ответы) — FIXED (спека).** Мутации теперь объявляют
|
||||
`{task}/{run}/{schedule}` (response-компоненты TaskMutation/RunMutation/
|
||||
ScheduleMutation), `GET /runs/{id}?logFromOffset` — RunLogChunk (allOf
|
||||
RunRecord + logChunk/logTotalLength). Генератор выдаёт **InlineObjectN**-
|
||||
модели (поля task/run/schedule/ok), десериализация нативная. `raw_ops.py`
|
||||
из примера **удалён**.
|
||||
- **Гоча 2 (const:true) — FIXED.** `const` убран из спеки; `Health200Response.ok`
|
||||
= обычный `StrictBool`.
|
||||
- **Гоча 3 (oneOf+discriminator) — FIXED.** `Schedule` стал плоской схемой
|
||||
(`kind` + опциональные `cron/timezone/ms/at`); `rec.schedule.cron` читается
|
||||
с типизированной модели. Normalization живьём: `once`→`{kind:once, at:ISO}`,
|
||||
`interval`→`{kind:interval, ms}`.
|
||||
- **F-1 (health auth) — FIXED (сервер).** `/health` всегда открыт, auth —
|
||||
после health-роута; прочие роуты с ключом 401.
|
||||
- **F-5 (dedupKey fail-fast) — FIXED (сервер).** POST/PATCH /schedules с
|
||||
неизвестным top-level полем → 400 с именем поля.
|
||||
- Итог ретеста: **11/11 ранее-сырых операций идут через типизированный клиент,
|
||||
сьют 24/24, smoke 19/19** (коммит sched `d658ff0`).
|
||||
|
||||
Гочи 1–3 ниже — описание сломанного состояния round 1 (0.1.2) + паттерн обхода
|
||||
(потребительский escape-hatch, если спека где-то ещё сырая).
|
||||
|
||||
## Гоча 1 — ответы `{}` в спеке ломают десериализацию (главная)
|
||||
|
||||
@@ -47,20 +73,35 @@ updated: 2026-08-18
|
||||
модели приходит с `actual_instance=None` — правило (`cron`) недостижимо через
|
||||
модель, только через raw JSON: `raw["schedule"]["schedule"]["cron"]`.
|
||||
Касается любого oneOf+discriminator на этой версии генератора (3.1-ветка).
|
||||
Фикс (round 2): плоская output-схема вместо oneOf — `kind` + опциональные
|
||||
поля; per-kind валидация на сервере (parseScheduleEntry).
|
||||
|
||||
## Окружение (Windows)
|
||||
|
||||
- `openapi-generator` 7.x требует **Java 11+**: системная Java 8 падает на
|
||||
class-load; ставь `JAVA_HOME` на новый JDK (Temurin 25 работает).
|
||||
**Важно (round-2 уточнение):** CLI-обёртка (`@openapitools/openapi-generator-cli`)
|
||||
спавнит `java` из **PATH**, не из `JAVA_HOME` — одного JAVA_HOME мало:
|
||||
`$env:Path = "$env:JAVA_HOME\bin;" + $env:Path` до запуска, иначе
|
||||
UnsupportedClassVersionError (class file 55.0 vs JRE 52.0 = Java 8 в PATH).
|
||||
Запуск: `npx --yes @openapitools/openapi-generator-cli generate -i spec.json -g python -o out --additional-properties=packageName=...`
|
||||
- Wrapped-ответы, объявленные **инлайн в `components.responses`**, дают имена
|
||||
`InlineObject..InlineObjectN` и доступ `resp.schedule.schedule.cron` (двойной
|
||||
`.schedule`). Работает; красивее — именованные схемы в `components.schemas`.
|
||||
- `info.version` спеки НЕ бьётся вместе с версией пакета (в 0.1.2 и 0.2.0 —
|
||||
`0.1.0`); версия живёт только в package.json / dist-tags.
|
||||
- Windows excluded port ranges (Hyper-V/WinNAT) резервируют порты (напр. 8090/8091):
|
||||
`EACCES` на listen. Проверка: `netsh interface ipv4 show excludedportrange protocol=tcp`.
|
||||
- Консоль cp1251: не печатай `→`/`«»` в скриптах — `'charmap' codec can't encode`; ASCII-only.
|
||||
|
||||
## Паттерн обхода (потребитель, клиент не трогаем)
|
||||
## Паттерн обхода (потребитель, клиент не трогаем) — исторический
|
||||
|
||||
Тонкий raw-слой рядом с сгенерированным пакетом (в примере — `raw_ops.py`):
|
||||
Тонкий raw-слой рядом с сгенерированным пакетом (в примере был `raw_ops.py`):
|
||||
только операции, где спека `{}`, через `call_api`; остальное — через типизированный
|
||||
клиент. Сгенерированный пакет остаётся перегенерируемым.
|
||||
|
||||
Пример целиком: `sched/examples/admin-client-python/` (24/24 сьют, 19/19 smoke).
|
||||
> **Статус:** после round 2 (0.2.0) обход не нужен — `raw_ops.py` удалён из
|
||||
> примера. Паттерн остаётся escape-hatch'ем для сырых спек в других проектах.
|
||||
|
||||
Пример целиком: `sched/examples/admin-client-python/` (24/24 сьют, 19/19 smoke,
|
||||
typed-only).
|
||||
|
||||
Reference in New Issue
Block a user