Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 53 additions & 30 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ HTTP API, протокол HTTP, Postman, js-playwright. Уроки и само

Четыре спецификации на TypeSpec (`typespec/<app>/`) компилируются в OpenAPI
(`make compile` → `tsp-output/`), и каждую отдаёт свой мок prism. Рядом живёт
приложение на fastify (`custom-server/`) с рукописными эндпоинтами, которых в
спецификациях нет: `/http-api/rpc`, `/http-api/echo`, стрим и куки для курса про
протокол, статика. Снаружи всё сшивает Caddy на `$PORT`.
приложение на fastify (`custom-server/`) с рукописными эндпоинтами: `/http-api/rpc`,
`/http-api/echo`, стрим и куки для курса про протокол, статика, а также REST-маршруты
`/http-api/tasks` — их забрали у статичного мока: тот не умеет ни пагинации, ни
отбора по пути. Снаружи всё сшивает Caddy на `$PORT`.

```text
Caddy :$PORT
├── :4010 fastify rpc, echo, стрим, куки, статика, swagger-ui
├── :4010 fastify tasks, rpc, echo, стрим, куки, статика, swagger-ui
├── :4011 prism http-api
├── :4012 prism http-protocol
├── :4013 prism js-playwright
Expand Down Expand Up @@ -50,6 +51,13 @@ prism получает `/tasks`. Директива `handle /http-api/rpc` пр
статичный режим отдал бы вместо данных заглушки вида `"string"`. Чтобы перевести
любую из них на статику, сначала заводят `@example` во всех её моделях.

Маршруты `/http-api/tasks` не обслуживает ни один режим мока: они реализованы в
`custom-server/src/tasks-rest.js`. В статичном режиме пример отдаётся дословно,
поэтому `skip` и `limit` не применялись, а на любой `/tasks/{id}` приходила одна
и та же задача.
Спецификация их по-прежнему описывает, и по ней читают документацию, но
поведение задаёт код.

## Примеры ответов это текст уроков

Значения в `@example` подобраны под то, что уроки уже печатают:
Expand All @@ -63,28 +71,34 @@ prism получает `/tasks`. Директива `handle /http-api/rpc` пр
Правка этих значений это правка курса: заводится вместе с коммитом в
`courses/ru/http_api_course`.

Набор задач лежит **в двух местах**: примерами в `typespec/http-api/models/task.tsp`
и данными JSON-RPC в `custom-server/src/data/tasks.js`. Дублирование намеренное:
общего источника у статичного мока и рукописного эндпоинта нет. Обе копии
обязаны совпадать, потому что урок `400-kinds` сравнивает REST и RPC на одних и
тех же данных. Расхождение валит `make test`.
Набор задач лежит **в двух местах**: данными в
`custom-server/src/data/tasks.js`, откуда их берут и REST, и RPC через общий
`tasks-store.js`, и примерами в `typespec/http-api/models/task.tsp`, откуда их
берёт документация. Поведение задают данные, примеры нужны для Swagger UI, и
совпадать они обязаны: иначе документация расходится с ответами. Расхождение
валит `make test`.

## Коды ответов несут уроки

На этих кодах построены самостоятельные работы, и prism отдаёт их из
спецификации:
На этих кодах построены самостоятельные работы:

| Запрос | Код | Что показывает урок |
| Запрос | Код | Кто отдаёт |
| --- | --- | --- |
| `GET /nosuch` | 404 | адреса нет |
| `DELETE /tasks` | 405 | метод не тот |
| `POST /tasks` с `{}` | 422 | тело не проходит валидацию |
| `POST /posts` без токена | 401 | нужна аутентификация |
| `POST /posts` с токеном | 201 | создано |
| `DELETE /tasks/1` | 204 | удалено, тела нет |

Правка `@useAuth`, обязательных полей DTO или `CreatedResponse` меняет эти коды.
Проверку кодов держит `make test`.
| `GET /nosuch` | 404 | prism |
| `POST /posts` без токена | 401 | prism |
| `POST /posts` с токеном | 201 | prism |
| `DELETE /tasks` | 405 | `tasks-rest.js` |
| `POST /tasks` с `{}` | 422 | `tasks-rest.js` |
| `GET /tasks/999` | 404 | `tasks-rest.js` |
| `DELETE /tasks/1` | 204 | `tasks-rest.js` |

У кодов два источника, и теряются они по-разному. У prism код меняет правка
спецификации: `@useAuth`, обязательные поля DTO, `CreatedResponse`. У `/tasks`
код написан руками, поэтому там его легко потерять рефакторингом — в частности
405 держится отдельными маршрутами на неподходящие методы, иначе fastify ответил
бы 404 на существующий адрес.

Проверку всех кодов держит `make test`.

## Версии прибиты не для порядка

Expand Down Expand Up @@ -130,17 +144,26 @@ make deploy APP=http_example HOST=timeweb SKIP=caddy,cron
Правка `Caddyfile` этого репозитория деплоится вместе с образом; `Caddyfile`
самого сервера живёт в own-heroku и к этому репозиторию отношения не имеет.

## Известное ограничение
## Что мок всё ещё не умеет

У `/tasks` пагинация и отбор по пути работают, потому что эти маршруты
реализованы кодом. Остальные коллекции по-прежнему за статичным моком, и там
ограничение в силе: `skip` и `limit` не применяются, а `/users/1/posts` отдаёт
тот же список, что `/posts`. Поэтому все посты в примерах приписаны автору 1 —
иначе два списка противоречат друг другу.

Лечится тем же способом, что `/tasks`: маршруты переносятся в `custom-server` на
общий модуль данных, а коды из таблицы выше воспроизводятся руками и закрываются
прогоном.

В статичном режиме пример возвращается дословно, поэтому `skip` и `limit` не
применяются, а записи по пути не отбираются: `GET /tasks/2` отдаёт ту же
задачу, что `/tasks/1`, а `/users/1/posts` — тот же список, что `/posts`.
Из-за последнего все посты в примерах приписаны автору 1: иначе два списка
противоречат друг другу.
## Набор данных не меняется

Уроки под это подогнаны, и в их тексте стоят скрытые пометки. Починка —
перенести `/tasks` с мока на реализацию в `custom-server`, сохранив коды из
таблицы: issue #16, тикет FEEDBACK-371.
`POST` и `DELETE` отвечают 201 и 204, но список задач остаётся прежним: создание
и удаление только сообщают, что произошло бы. Сервер учебный, запросы к нему идут
одновременно от множества студентов, и мутации сделали бы уроки
невоспроизводимыми: самостоятельная описывает один набор, а следующий студент
получил бы другой. Прогон `make test` проверяет, что после `POST` набор задач
остался прежним.

## Команды

Expand Down
12 changes: 12 additions & 0 deletions Caddyfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ handle /http-api/rpc {
reverse_proxy localhost:4010
}

# /tasks обслуживает приложение, а не мок prism: мок отдавал пример дословно и
# поэтому не применял skip и limit и не отбирал записи по пути. Блоки заданы
# точно, без tasks*, чтобы не перехватывать посторонние адреса. Префикс здесь не
# срезается, поэтому приложение регистрирует полные пути.
handle /http-api/tasks {
reverse_proxy localhost:4010
}

handle /http-api/tasks/* {
reverse_proxy localhost:4010
}

handle /http-api-openapi* {
reverse_proxy localhost:4010
}
Expand Down
Loading