Skip to content

Latest commit

 

History

History
108 lines (78 loc) · 12.1 KB

README.md

File metadata and controls

108 lines (78 loc) · 12.1 KB

http-example

Учебный HTTP-сервер Хекслета: https://http.hexlet.app. На него живьём ходят студенты из курсов HTTP API, протокол HTTP, Postman, js-playwright и курсов Selenium и Playwright, а уроки и самостоятельные работы цитируют его ответы дословно, вплоть до значений полей.

Отсюда главное свойство проекта: ответы сервера это контент курса, а не деталь реализации. Правка данных здесь делает неверным текст урока в другом репозитории, и по коду это не видно. Поэтому правила работы с проектом собраны в AGENTS.md, и читать их стоит до первой правки — там же разобрано, почему наборы данных такого размера, почему они не меняются и какие коды ответов несут уроки.

Устройство короткое: четыре спецификации на TypeSpec (typespec/<app>/, по одной на курс) компилируются в OpenAPI, а маршруты, валидацию и авторизацию строит из них fastify-openapi-glue. Руками написаны только данные и то, что в OpenAPI не выражается. Значит документация и поведение разъехаться не могут: студент читает ту же спецификацию, по которой работает сервер.

Примеры форматов тела

Урок body-formats курса HTTP для автоматизации использует следующие адреса. Обработчики показывают полученные данные без сохранения задач.

Метод и путь Результат
GET /http-protocol/form HTML-форма с полями title и description
POST /http-protocol/form Полученные значения обоих полей обычным текстом
POST /http-protocol/body JSON с заголовками запроса и данными в json, form или files
GET /http-protocol/image.png Файл PNG размером 8090 байтов

Обработчик body принимает JSON, application/x-www-form-urlencoded и multipart. Для примера с файлом он возвращает его содержимое как строку UTF-8. Лимиты multipart допускают один файл до 64 КиБ и до десяти текстовых полей по 4 КиБ. Исходное тестовое изображение взято из httpbin, который распространяется под лицензией MIT.

Учебные приложения для UI-тестов

Курсы Selenium и Playwright тестируют маленькие приложения под префиксом своего курса. У каждого своя предметная область, и страницы в нём появились из её сценариев. Уроки ищут элементы и проверяют тексты дословно, поэтому локаторы и надписи этих страниц тоже контент курса.

/java-selenium, библиотека City Library. Курс разбирает действия пользователя, окна и фреймы, и у каждого действия в библиотеке есть смысл.

Путь Сценарий
/java-selenium каталог, h1 «City Library»
/java-selenium/login → /my-shelf вход читателя reader / books123, полка с выданными книгами
/java-selenium/covers обложки .figure, название .figcaption h5 видно при наведении, двойной клик добавляет книгу в избранное
/java-selenium/shelves книга #book-moby-dick перетаскивается на полку #shelf-reading
/java-selenium/search поиск #search фильтрует каталог, Enter печатает число найденного в #result
/java-selenium/return кнопка #return-book спрашивает confirm перед возвратом
/java-selenium/preview «Open preview» открывает отрывок в новом окне
/java-selenium/reader глава книги во фрейме chapter, абзац #content

/python-selenium, трекер Task Board. Курс разбирает сессию, куки, ожидания и мобильное меню.

Путь Сценарий
/python-selenium промо-страница, первая ссылка «Sign in» после названия
/python-selenium/login → /tasks вход student / tasks123, список задач, меню #menu-button с пунктами .menu-item

/python-playwright, табло Departures. Курс настраивает контекст браузера, и табло на эти настройки отвечает.

Путь Сценарий
/python-playwright табло #departures, время вылета печатается в часовом поясе браузера, на узком экране строки складываются в карточки
/python-playwright/login → /trips вход пассажира passenger / flight123, «My trips»

У всех трёх одинаковое устройство входа. Форма #login с полями #username и #password и кнопкой button.primary[data-test=login-button], флеш-сообщение #flash, выход по /<курс>/logout. Приложения описаны конфигом apps в custom-server/src/ui-pages.ts, страницы лежат фрагментами в custom-server/assets/ui-pages/<курс>/, префикс в них записан как {{prefix}}.

Демонстрации HTTP для автоматизации

Обработчики сессии, кеширования, событий и повторных запросов живут под префиксом курса /http-for-automation. Общие коллекции задач, пользователей и публикаций сохраняются.

Метод и путь Результат
GET /http-for-automation/login-form Форма с учебным именем student
POST /http-for-automation/session Куки session=hexlet-demo на пять минут
GET /http-for-automation/session Guest без куки, Welcome, student! с учебной куки
DELETE /http-for-automation/session Удаление куки клиента
GET /http-for-automation/cache Расписание, ETag и private, max-age=60
GET /http-for-automation/cache/revalidate То же расписание с no-cache
GET /http-for-automation/cache/no-store То же расписание с no-store
POST /http-for-automation/webhooks/inboxes Новый приёмник, его callback_url и events_url
POST /http-for-automation/webhooks/inboxes/{id}/subscription Подписка с полученным callback_url
POST /http-for-automation/webhooks/inboxes/{id}/trigger Отправка учебного события настоящим HTTP-запросом в свой приёмник
GET /http-for-automation/webhooks/inboxes/{id}/events Сохранённые входящие сообщения и ответы приёмника
POST /http-for-automation/reliability/runs Новый отдельный опыт с run_id и base_url
GET {base_url}/temporary Первый ответ 503 с Retry-After: 1, следующий 200
GET {base_url}/limited 429 с Retry-After: 1, после ожидания 200
GET {base_url}/slow Ответ через две секунды для проверки таймаута
POST {base_url}/operations?lose_response=1 Создание операции с обрывом связи до ответа
GET {base_url}/operations Результаты созданных операций
GET {base_url}/journal Связь попыток с результатами операций

Вебхуки принимают только подготовленные поля события. Подписка допускает приёмник этого же опыта, произвольные внешние адреса не вызываются. Реальный HTTP-запрос идёт на локальный порт приложения, за тем же публичным адресом. Получатель проверяет учебный X-Webhook-Key: hexlet-demo-webhook и подтверждает сохранение сообщения кодом 204. Этот общедоступный пример показывает форму проверки источника, настоящие учётные данные не используются.

При создании операции поле title обязательно. Если Idempotency-Key повторяется с тем же названием, сервер возвращает существующую операцию. Другое название под тем же ключом даёт 409. Без ключа каждый запрос создаёт отдельную запись. Параметр lose_response=1 закрывает соединение после записи новой операции; уже найденная по ключу операция возвращается обычным ответом. При обращении через Caddy первый обрыв превращается в ответ 502 без результата операции. Это тоже оставляет клиенту задачу проверить, было ли изменение выполнено.

Приёмник и опыт живут 30 минут, данные хранятся только в памяти. Число опытов и размеры журналов ограничены. После истечения срока или перезапуска создаётся новый опыт. Фиксированный маркер сессии служит для демонстрации обмена куки, проверку настоящего аккаунта он не выполняет.

Prerequisites

  • mise (ставит Node, pnpm, Caddy и jactionlint по mise.toml)
  • Docker (только для compose:*)

Commands

mise run setup           # зависимости и компиляция спецификаций
mise run check           # типы, линтеры, сгенерированное, тесты
mise run test            # только тесты, против всех четырёх префиксов
mise daemons start       # приложение и Caddy на http://localhost:8080
mise run compose:build
mise run compose:up      # http://localhost:8080

Остальные задачи: mise tasks.


Hexlet Ltd. logo

This repository is created and maintained by the team and the community of Hexlet, an educational project. Read more about Hexlet.