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
42 changes: 23 additions & 19 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ HTTP API, протокол HTTP, Postman, js-playwright. Уроки и само
(`make compile` → `tsp-output/`), и каждую отдаёт свой мок prism. Рядом живёт
приложение на fastify (`custom-server/`) с рукописными эндпоинтами: `/http-api/rpc`,
`/http-api/echo`, стрим и куки для курса про протокол, статика, а также REST-маршруты
`/http-api/tasks` — их забрали у статичного мока: тот не умеет ни пагинации, ни
отбора по пути. Снаружи всё сшивает Caddy на `$PORT`.
коллекций `/http-api/tasks`, `/users`, `/posts`, `/comments` — их забрали у
статичного мока: тот не умеет ни пагинации, ни выборки полей, ни отбора по пути.
Снаружи всё сшивает Caddy на `$PORT`.

```text
Caddy :$PORT
├── :4010 fastify tasks, rpc, echo, стрим, куки, статика, swagger-ui
├── :4011 prism http-api
├── :4010 fastify коллекции, rpc, echo, стрим, куки, статика, swagger-ui
├── :4011 prism http-api: только /courses и /login
├── :4012 prism http-protocol
├── :4013 prism js-playwright
└── :4014 prism postman
Expand Down Expand Up @@ -87,16 +88,18 @@ prism получает `/tasks`. Директива `handle /http-api/rpc` пр
| `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` |
| `DELETE /tasks` | 405 | `routes.js` |
| `POST /tasks` с `{}` | 422 | `routes.js` |
| `GET /tasks/999` | 404 | `routes.js` |
| `DELETE /tasks/1` | 204 | `routes.js` |
| `POST /posts` без токена | 401 | `routes.js` |

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

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

Expand Down Expand Up @@ -144,17 +147,18 @@ 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` на
общий модуль данных, а коды из таблицы выше воспроизводятся руками и закрываются
прогоном.
* пользователей десять — урок `example` объясняет пагинацию тем, что `total`
равен 10, а `?skip=30` отдаёт пустую страницу;
* постов сорок — тот же урок учит на `?skip=30`, значит записей нужно заметно
больше тридцати;
* у автора 1 восемь постов — урок показывает вложенный ресурс
`/users/1/posts`, и на пустом списке он ничего не объясняет;
* первые три пользователя и первые два поста автора 1 приведены в уроке
дословно.

## Набор данных не меняется

Expand Down
82 changes: 56 additions & 26 deletions Caddyfile
Original file line number Diff line number Diff line change
@@ -1,100 +1,130 @@
:{$PORT}

# Апстримы указаны адресом, а не именем localhost: и prism, и приложение слушают
# только IPv4 (0.0.0.0), а localhost резолвится ещё и в ::1, где не слушает никто.

# http-api course
handle /http-api/echo {
reverse_proxy localhost:4010
reverse_proxy 127.0.0.1:4010
}

handle /http-api/rpc {
reverse_proxy localhost:4010
reverse_proxy 127.0.0.1:4010
}

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

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

handle /http-api/users {
reverse_proxy 127.0.0.1:4010
}

handle /http-api/users/* {
reverse_proxy 127.0.0.1:4010
}

handle /http-api/posts {
reverse_proxy 127.0.0.1:4010
}

handle /http-api/posts/* {
reverse_proxy 127.0.0.1:4010
}

handle /http-api/comments {
reverse_proxy 127.0.0.1:4010
}

handle /http-api/comments/* {
reverse_proxy 127.0.0.1:4010
}

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

handle_path /http-api/* {
reverse_proxy localhost:4011
reverse_proxy 127.0.0.1:4011
}

# http-protocol course
handle /http-protocol/example {
reverse_proxy localhost:4010
reverse_proxy 127.0.0.1:4010
}

handle /http-protocol/login {
reverse_proxy localhost:4010
reverse_proxy 127.0.0.1:4010
}

handle /http-protocol/stream {
reverse_proxy localhost:4010
reverse_proxy 127.0.0.1:4010
}

handle /http-protocol/removed {
reverse_proxy localhost:4010
reverse_proxy 127.0.0.1:4010
}

handle /http-protocol {
reverse_proxy localhost:4010
reverse_proxy 127.0.0.1:4010
}

handle /http-protocol-openapi* {
reverse_proxy localhost:4010
reverse_proxy 127.0.0.1:4010
}

handle_path /http-protocol/* {
reverse_proxy localhost:4012
reverse_proxy 127.0.0.1:4012
}

# js-playwright course
handle /js-playwright/users-list {
reverse_proxy localhost:4010
reverse_proxy 127.0.0.1:4010
}

handle /js-playwright-openapi* {
reverse_proxy localhost:4010
reverse_proxy 127.0.0.1:4010
}

handle_path /js-playwright/* {
reverse_proxy localhost:4013
reverse_proxy 127.0.0.1:4013
}

# postman course
handle /postman/cookie {
reverse_proxy localhost:4010
reverse_proxy 127.0.0.1:4010
}

handle /postman-openapi* {
reverse_proxy localhost:4010
reverse_proxy 127.0.0.1:4010
}

handle_path /postman/* {
reverse_proxy localhost:4014
reverse_proxy 127.0.0.1:4014
}

# js-dom-testing-library course
handle /js-dom-testing-library/users-list {
reverse_proxy localhost:4010
reverse_proxy 127.0.0.1:4010
}

# shared/static
handle /assets* {
reverse_proxy localhost:4010
reverse_proxy 127.0.0.1:4010
}

# default
handle {
reverse_proxy localhost:4010
reverse_proxy 127.0.0.1:4010
}
Loading