Skip to content

feat(specs): обслуживать все четыре спецификации приложением - #20

Merged
fey merged 1 commit into
mainfrom
feat/all-specs-from-openapi
Aug 14, 2026
Merged

feat(specs): обслуживать все четыре спецификации приложением#20
fey merged 1 commit into
mainfrom
feat/all-specs-from-openapi

Conversation

@fey

@fey fey commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Закрывает по существу FEEDBACK-374. Сделано на фундаменте из 187d480: маршруты строятся из спецификации, а не пишутся руками.

Зачем

Курс HTTP API уже собирался из спецификации, а Postman, Playwright и HTTP-протокол оставались за моком prism на данных faker'а. В курсе Postman это ломало урок 200-complex-requests целиком:

Урок обещает Было Стало
?limit=2 — двух первых 4 записи, limit в ответе 10928880 2 записи, limit 2, total 10
?skip=3&limit=2 0 записей пользователи 4 и 5
?skip=3&limit=5 мусор пользователи 4–8
/users/3 id: 52956988, имя ea nulla sed cupidatat nostrud id: 3, Reinhold Langosh

Что сделано

openapi-spec.ts (бывший http-api.ts) стал плагином на одну спецификацию и регистрируется по разу на каждую; имя приходит параметром из app.config.json, того же списка, что задаёт маршруты документации.

Обработчики одни на все четыре: имена интерфейсов совпадают, значит совпадают и operationId, а js-playwright просто подмножество. Отсутствующий обработчик glue находит на старте и падает громко, поэтому расхождение не будет тихим.

В три спецификации добавлены @operationId и подключён @typespec/openapi, без которого декоратор неизвестен. Заодно они приведены к виду http-api: skip и limit объявлены uint16 со значениями по умолчанию, у чтения одной записи, обновления и удаления объявлен 404, у создания CreatedResponse.

Про значения по умолчанию отдельно: их применяет валидатор, и без них пагинация не работает вовсе. Ровно это я и наблюдал на промежуточном прогоне — skip применялся, а limit нет.

Три настоящих различия, снятых со спецификаций

  • BasicAuth добавлен в securityHandlers: задачи курса Postman закрыты именно им, включая чтение одной задачи.
  • Создание приведено к 201 во всех четырёх. Три спецификации объявляли обычный ответ, то есть 200, и урок 850-api-testing курса Playwright из-за этого не проходил, хотя учил правильному коду и ассертил 201. Выровнены спецификации, а не урок: ни один другой курс на 200 при создании не опирается.
  • authService у http-protocol удалён. По адресу /http-protocol/login живёт рукописный эндпоинт: курс разбирает отправку формы через telnet и печатает ответ Done! с Content-Length: 5. Спецификация описывала выдачу токена, то есть то, чего этот адрес никогда не отдавал, и glue падал на дубле маршрута.

Мока больше нет

Ни одного prism не поднимается, зависимость @stoplight/prism-cli снята, Caddy направляет все четыре префикса приложению. Мины прибитой версии (точная 5.14.2, обязательный --multiprocess=false) сохранены в AGENTS.md на случай возврата.

Заодно починен регресс из предыдущей пачки

Адрес документации со слешем на конце отдавал 405 вместо страницы: swagger-ui регистрирует на него и GET, и добавленный fastify HEAD, а fastify-allow запоминает по маршруту последний метод, поэтому в Allow оставался только HEAD. Ссылка живая — урок crud ведёт на /http-api-openapi/#/Tasks, фрагмент после решётки до сервера не доходит. Прод сейчас отдаёт 200, новая сборка отдавала бы 405. Нормализуется четырьмя redir в Caddy.

Проверка

make test вырос до 168 проверок: по каждому префиксу пагинация, select, отбор по пути, 404, 405, 422 на отрицательном skip, состав коллекций, схемы авторизации, вложенные ресурсы, код создания.

Проверен на способность падать: если снять проверку Basic, падают две проверки postman.

Сверх прогона собран образ и поднят контейнер, запросы шли через Caddy: все четыре префикса, рукописные эндпоинты (/http-protocol/example, /stream, /removed, /http-protocol, /postman/cookie, /js-playwright/users-list, /js-dom-testing-library/users-list), POST /http-protocol/loginDone!, документация всех четырёх.

Правки курсов идут отдельно, после деплоя. Там уже найдено: урок 850-api-testing курса Playwright запрашивает /js-playwright/post/ (такого маршрута нет), а toMatchObject в нём сравнивает data сам с собой.

🤖 Generated with Claude Code

…нием

Курс HTTP API уже собирался из спецификации, а Postman, Playwright и
HTTP-протокол оставались за моком prism на данных faker'а. В курсе Postman это
ломало урок целиком: `?limit=2` отдавал четыре записи с `limit` равным 10928880,
`?skip=3&limit=2` ноль записей, а `/users/3` пользователя 52956988 с латинским
именем.

Теперь плагин openapi-spec.ts регистрируется по разу на каждую спецификацию, имя
приходит параметром из app.config.json. Обработчики одни на все четыре: имена
интерфейсов совпадают, значит совпадают и operationId, а js-playwright просто
подмножество. Отсутствующий обработчик glue находит на старте и падает громко.

В три спецификации добавлены @operationid и подключён @typespec/openapi, без
которого декоратор неизвестен. Заодно они приведены к тому же виду, что http-api:
skip и limit объявлены uint16 со значениями по умолчанию, у чтения одной записи,
обновления и удаления объявлен 404, у создания CreatedResponse.

Значения по умолчанию тут не украшение: их применяет валидатор, и без них
пагинация не работает вовсе. Скрытая правка одного этого места и была причиной,
по которой skip применялся, а limit нет.

Создание приведено к 201 во всех четырёх. Три спецификации объявляли обычный
ответ, то есть 200, и урок 850-api-testing курса Playwright из-за этого не
проходил, хотя учил правильному коду и ассертил 201.

BasicAuth добавлен в securityHandlers: задачи курса Postman закрыты именно им, и
включая чтение одной задачи. Схема берётся из спецификации, как и остальные.

authService у http-protocol удалён. По адресу /http-protocol/login живёт
рукописный эндпоинт: курс разбирает отправку формы через telnet и печатает ответ
`Done!` с Content-Length 5. Спецификация же описывала выдачу токена, то есть то,
чего этот адрес никогда не отдавал, и glue из-за этого падал на дубле маршрута.

Моков prism больше нет ни одного, зависимость снята. Caddy направляет все четыре
префикса приложению.

Отдельно починен адрес документации со слешем на конце: swagger-ui регистрирует
на него и GET, и добавленный fastify HEAD, а fastify-allow запоминает по маршруту
последний метод, поэтому в Allow оставался только HEAD и браузерный GET получал
405. Ссылка живая, урок crud ведёт на /http-api-openapi/#/Tasks. Нормализуется
через redir в Caddy.

Прогон вырос до 168 проверок и проверяет все четыре префикса.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@fey
fey merged commit 17d07b3 into main Aug 14, 2026
2 checks passed
@fey
fey deleted the feat/all-specs-from-openapi branch August 14, 2026 16:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant