Практикум REST и WebSocket — итоги
Кратко — что стоит унести из практикума OrderDesk: два сервиса на портах 8100 и 5200, контракт /api/v1, межсервисный REST и WebSocket к клиенту. Если ответ в FAQ кажется общим — откройте шаг из маршрута или оглавление раздела. Для самопроверки — чек-лист.
FAQ — Часто задаваемые вопросы
Типичные сбои OrderDesk и ответы на частые запросы в поиске ("REST API что это", "JWT как работает", "WebSocket vs polling", "тест API в Postman"). Краткий ответ здесь; разбор — в шагах практикума. Заучивание — в чек-листе.
Вопрос. Postman или curl пишет "connection refused" на localhost:8100.
Ответ. catalog-api не слушает порт: поднимите FastAPI (uvicorn app.main:app --reload --port 8100 из каталога проекта), проверьте firewall и что порт не занят другим процессом. Swagger http://localhost:8100/docs должен открываться в браузере. Подробнее — шаг 4.
Вопрос. "Connection refused" на localhost:5200 при создании заказа.
Ответ. orders-api не запущен: dotnet run в папке сервиса, в логах — Now listening on: http://localhost:5200. Каталог может быть жив, но без orders-api JWT и POST /orders недоступны. Подробнее — шаг 5.
Вопрос. POST /api/v1/orders возвращает 401 Unauthorized.
Ответ. Для клиентских ручек нужен Bearer JWT: сначала POST /api/v1/auth/token, затем заголовок Authorization: Bearer {{access_token}}. Пустое окружение Postman или просроченный токен дают тот же 401. Подробнее — шаг 6, шаг 8.
Вопрос. POST /api/v1/reservations в каталоге отвечает 401 — ключ вроде указан.
Ответ. Межсервисные вызовы требуют заголовок X-Api-Key, совпадающий с CATALOG_API_KEY (Python) и Catalog:ApiKey (C#). Опечатка, пробел в конце строки или разные значения в двух appsettings/.env — частая причина. Сравнивайте через secrets.compare_digest на стороне каталога. Подробнее — шаг 6.
Вопрос. Клиент получает 403 Forbidden на GET /api/v1/orders/{id}.
Ответ. JWT валиден, но субъект токена не совпадает с владельцем заказа (проверка sub / user id). В учебном стенде залогиньтесь тем же пользователем, что создавал заказ, или ослабьте политику только в dev. Подробнее — шаг 5.
Вопрос. POST /api/v1/orders возвращает 502 Bad Gateway.
Ответ. orders-api не достучался до catalog-api (сервис остановлен, неверный Catalog:BaseUrl, таймаут HttpClient). Ожидайте Problem Details с кодом 502, а не необработанное 500. Проверьте http://localhost:8100/health и логи обоих процессов. Подробнее — шаг 5, интерактив "Catalog down".
Вопрос. Резерв или заказ завершается 409 Conflict.
Ответ. Нехватка остатка (stockAvailable) или конфликт бизнес-правила. В негативном сценарии Postman quantity: 9999 как раз должен дать 409. Повтор с тем же телом без идемпотентности не должен списывать остаток дважды — см. Idempotency-Key. Подробнее — шаг 2, шаг 4.
Вопрос. Браузерный фронтенд пишет "blocked by CORS policy", Postman — 200.
Ответ. CORS проверяет только браузер: origin фронта должен быть в списке WithOrigins на orders-api (и при прямых вызовах каталога — на FastAPI). Postman CORS не эмулирует. Проверьте preflight OPTIONS и заголовки Access-Control-*. Подробнее — шаг 6.
Вопрос. Раньше работало, сейчас 401 — "JWT expired" или invalid signature.
Ответ. Access token короткоживущий: запросите новый через POST /auth/token. При смене Jwt:SigningKey в конфиге все старые токены станут невалидными. Сверьте Issuer, Audience и часы на машине (clock skew). Подробнее — шаг 6.
Вопрос. WebSocket в Postman подключается и сразу обрывается.
Ответ. URL должен быть ws://localhost:5200/ws/orders?access_token=<jwt> с свежим токеном. Пустой или просроченный access_token в query даёт закрытие с 401. Убедитесь, что orders-api запущен и middleware JWT читает query (см. OnMessageReceived). Подробнее — шаг 7.
Вопрос. После POST /orders в WebSocket нет события order.status_changed.
Ответ. Подключение WS должно быть до или сразу после создания заказа, под тем же sub, что в JWT. Hub рассылает только подписчикам пользователя; проверьте JSON type и версию v. В логах orders-api — факт вызова BroadcastAsync. Подробнее — шаг 7, шаг 8.
Вопрос. Остановил catalog-api — заказы всё равно 201, ожидал 502.
Ответ. Возможен кэш/мок в Postman, запрос ушёл не на локальный orders_base, или в коде нет ветки Problem Details при ошибке HttpClient. Повторите с выключенным uvicorn и catalog_base = http://localhost:8100. В песочнице на intro сценарий "Catalog down" показывает ожидаемый 502.
Вопрос. orders-api в логах "Invalid API key", хотя в Postman ключ верный.
Ответ. Ключ в Postman для ручного вызова каталога (api_key) должен совпадать с тем, что orders-api шлёт исходящим X-Api-Key. Это два разных места: переменная окружения Postman и Catalog:ApiKey в appsettings.Development.json. Подробнее — шаг 8.
Вопрос. В Postman {{product_id}} подставляется пустым.
Ответ. Выбрано окружение OrderDesk Local, в Tests запроса "создать товар" есть pm.environment.set("product_id", body.id) и статус 201. Без активного environment переменные не сохраняются. Порядок запросов в коллекции — как в шаге 8.
Вопрос. Повтор POST /reservations с тем же Idempotency-Key — что должно быть?
Ответ. Идемпотентность: второй запрос с тем же ключом возвращает тот же reservationId и 201 (или 200 по вашей реализации), без повторного списания остатка. Без ключа сеть после таймаута может создать дубликат. Подробнее — шаг 4, шаг 6.
Вопрос. Два одинаковых заказа после обрыва сети на POST /orders.
Ответ. Клиент повторил запрос без стабильного Idempotency-Key / requestId. В практикуме ключ резерва строится как {orderId}:{productId} на стороне orders-api — при повторе оркестрации каталог не должен резервировать дважды. Добавьте ключ на уровне создания заказа в проде. Подробнее — шаг 5.
Вопрос. Swagger каталога открывается, orders-api пишет timeout к catalog.
Ответ. В Catalog:BaseUrl опечатка (https вместо http, лишний слэш, порт 8000 вместо 8100), Docker hostname catalog без compose-сети. С хоста Windows/Mac для локального запуска обычно http://localhost:8100. Подробнее — шаг 5.
Вопрос. 422 Unprocessable Entity на POST /api/v1/products.
Ответ. Тело не проходит Pydantic-схему: отрицательный price, отсутствует sku, неверные типы. Сверьте JSON с контрактом в шаге 2 и примером в шаге 8.
Вопрос. В логах catalog и orders разный X-Request-Id для одного заказа.
Ответ. Сквозная трассировка: клиент (или Pre-request Script коллекции) задаёт X-Request-Id, orders-api пробрасывает его в HttpClient к каталогу. Без проброса разбор инцидента затруднён. Подробнее — шаг 6, шаг 8.
Вопрос. GET /api/v1/products из браузера с другого порта — CORS, из orders-api — нет.
Ответ. Публичные GET каталога в учебной модели могут быть открыты, но браузер всё равно требует CORS при cross-origin. Сервер-сервер (HttpClient) CORS не использует. Настройте политику или проксируйте через orders-api. Подробнее — шаг 6.
Вопрос. WebSocket ping/pong — зачем, если TCP keep-alive есть?
Ответ. Прокси и балансировщики могут рвать "тихие" долгие WS; прикладной ping/pong в JSON подтверждает живость канала и логику hub. Подробнее — шаг 7.
Вопрос. dotnet run слушает другой порт, не 5200.
Ответ. Проверьте launchSettings.json, ASPNETCORE_URLS и явный app.Run("http://localhost:5200") из практикума. Postman orders_base должен совпадать с фактическим URL. Подробнее — шаг 5.
Вопрос. uvicorn: Error loading ASGI app — модуль не найден.
Ответ. Команду запускайте из корня проекта catalog-api, где лежит пакет app, с активированным venv и установленными зависимостями (pip install -r requirements.txt). Путь app.main:app чувствителен к структуре каталогов. Подробнее — шаг 4.
Вопрос. DTO в ответе заказа не совпадает с телом запроса — "сломали контракт"?
Ответ. Ответ 201 часто обогащён полями (status, lines, id резерва). Сверьте OpenAPI и таблицу маппинга entity ↔ DTO в шаге 3. Клиент парсит только документированные поля.
Вопрос. Newman/CI падает на негативных тестах 409/502.
Ответ. В папке Negative в Tests должен быть assert на ожидаемый статус (pm.response.to.have.status(409)), а не на 201. Для 502 каталог перед прогоном останавливают. Подробнее — шаг 8.
Вопрос. Песочница на intro показывает 502, локальный код — 500 без тела.
Ответ. Доведите обработчик исключений HttpClient до Problem Details и кода 502, как в контракте шага 2. Необработанное исключение ASP.NET даёт 500. Сверьтесь с чек-листом в шаге 5.
Вопрос. Где теория про REST, JWT и WebSocket вне этого практикума?
Ответ. 8.05 Микросервисы и интеграция — REST, проектирование API, реактивные транспорты; HTTP — 2.09. Практикум 8.08 — применение на OrderDesk.
Вопрос. REST API — что это простыми словами?
Ответ. REST — стиль построения HTTP API вокруг ресурсов (товар, заказ) и методов GET/POST/DELETE с предсказуемыми кодами ответа. В OrderDesk контракт зафиксирован под префиксом /api/v1. Теория — 8.05 intro, практика — шаг 2.
Вопрос. Чем REST отличается от SOAP и gRPC для учебного проекта?
Ответ. REST + JSON проще отлаживать в Postman и браузере; SOAP и gRPC требуют отдельных контрактов и стеков. Практикум 8.08 сознательно на HTTP/JSON между catalog-api и orders-api. Сравнение подходов — 8.05 intro, ресурсы OrderDesk — шаг 1.
Вопрос. WebSocket и polling — что выбрать для статуса заказа?
Ответ. Polling (GET /orders/{id} раз в N секунд) нагружает API и даёт задержку. WebSocket держит канал и шлёт order.status_changed сразу после смены статуса — так устроен UI в практикуме. Протокол событий — шаг 7, сценарий — intro.
Вопрос. JWT — как работает access token в OrderDesk?
Ответ. Клиент получает JWT через POST /api/v1/auth/token, затем передаёт его в заголовке Authorization: Bearer … или в query WebSocket. Сервер проверяет подпись, exp, iss, aud и субъект sub для доступа к заказам. Настройка — шаг 6, проверка — шаг 8.
Вопрос. Bearer token в Postman — куда вставлять для REST?
Ответ. Вкладка Authorization → Bearer Token, значение {{access_token}} после запроса "получить токен". Для ручек каталога от клиента JWT обычно не нужен; межсервисно — отдельно X-Api-Key. Коллекция — шаг 8, политика — шаг 6.
Вопрос. Как тестировать REST API в Postman с нуля?
Ответ. Импортируйте коллекцию OrderDesk, активируйте окружение OrderDesk Local, поднимите catalog (8100) и orders (5200), пройдите цепочку: товар → токен → заказ → WS. Пошагово — шаг 8, оглавление — intro.
Вопрос. OpenAPI и Swagger — зачем /docs на каталоге?
Ответ. OpenAPI описывает схемы запросов/ответов; Swagger UI на http://localhost:8100/docs даёт интерактивные вызовы без Postman. Контракт /api/v1 согласован в шаге 2, реализация FastAPI — шаг 4.
Вопрос. HTTP 401 и 403 — в чём разница в API заказов?
Ответ. 401 — нет или просрочен JWT (не аутентифицирован). 403 — токен валиден, но субъект не владелец ресурса (доступ запрещён). Коды заложены в контракт шага 2, проверка владельца — шаг 5.
Вопрос. Idempotency-Key на POST — зачем нужен в API?
Ответ. Повтор сети после таймаута не должен дважды списать остаток или создать второй заказ. Ключ связывает повтор с тем же результатом. Резерв в каталоге — шаг 4, оркестрация — шаг 5.
Вопрос. X-Api-Key между микросервисами — это замена JWT?
Ответ. JWT — для внешнего клиента (браузер, Postman от лица пользователя). X-Api-Key — доверенный канал orders-api → catalog-api, без пользовательского контекста. Сравнение секретов — шаг 6, сценарий OrderDesk — шаг 1.
Вопрос. Зачем в практикуме два сервиса на портах 8100 и 5200?
Ответ. catalog-api владеет остатками, orders-api владеет заказами и оркестрирует резерв по REST — так видна граница микросервисов и типичные сбои (502, ключи). Архитектура — шаг 1, теория границ — 8.05 intro.
Вопрос. Problem Details (RFC 7807) — что клиент видит при 502?
Ответ. Структурированное тело с type, title, status вместо пустого 500 — orders-api сообщает, что каталог недоступен, а не "сломался сам". Контракт ошибок — шаг 2, обработчик — шаг 5.
Вопрос. CORS policy в браузере — почему Postman работает без настройки?
Ответ. CORS проверяет только браузер при cross-origin; Postman и curl ограничений origin не имеют. Для фронта на другом порту настройте WithOrigins на orders-api. Подробнее — шаг 6, интерактив — intro.
Вопрос. Оркестрация заказа через REST — какие шаги между сервисами?
Ответ. POST /orders в orders-api → POST /reservations в catalog с API-ключом → ответ клиенту → push статуса по WebSocket. Диаграмма потоков — шаг 1, код C# — шаг 5.
Вопрос. FastAPI и ASP.NET Core — почему два языка в одном практикуме?
Ответ. Учебный стенд показывает реальную интеграцию разнородных команд: Python-каталог и C#-заказы по общему HTTP-контракту. Каталог — шаг 4, заказы — шаг 5.
Вопрос. Версия API /api/v1 — зачем префикс в URL?
Ответ. Позволяет выпустить v2 без поломки старых клиентов; все ручки практикума живут под одной версией. Проектирование ресурсов — шаг 2, маппинг DTO — шаг 3.
Вопрос. HttpClient из C# к Python — типичные ошибки BaseUrl?
Ответ. Неверный порт (8000 вместо 8100), https локально, лишний слэш, hostname catalog без Docker-сети — приводят к таймауту и 502 на клиенте. Настройка Catalog:BaseUrl — шаг 5, health каталога — шаг 4.
Вопрос. WebSocket ws://localhost:5200/ws/orders — когда подключаться?
Ответ. До или сразу после POST /orders, с свежим access_token в query — иначе hub закроет соединение. Протокол JSON и heartbeat — шаг 7, проверка в Postman — шаг 8.
Вопрос. Событие order.status_changed — что слать клиенту вместо опроса?
Ответ. JSON с полями type, v, id заказа и новый status — UI обновляется без периодического GET. Hub и broadcast — шаг 7, E2E — шаг 8.
Вопрос. С чего начать практикум REST и WebSocket 8.08?
Ответ. Прочитайте intro и шаг 1, затем контракт шаг 2, поднимите сервисы 4–5, закройте чек-лист. База по интеграциям — 8.05 intro.
Резюме раздела
- catalog-api (Python, FastAPI, порт
8100) — единственный владелец остатков: товары,POST/DELETEрезервов, SQLite в учебной сборке, входящийX-Api-KeyиIdempotency-Keyна резерве. - orders-api (C#, ASP.NET Core 8, порт
5200) — заказы, оркестрация резерва по REST, JWT для внешних клиентов,502при недоступном каталоге. - JWT — короткий access token после
POST /api/v1/auth/token; для WebSocket тот же токен в queryaccess_token; ключ подписи из окружения, не из git. - API-ключ — только межсервисный канал orders → catalog (
X-Api-Key), сравнение черезsecrets.compare_digest, ротация двумя активными ключами в проде. - WebSocket —
ws://localhost:5200/ws/orders, JSON-событияorder.status_changed,ping/pong, push статусов без polling UI.
Маршрут по статьям
| Шаг | Статья | Содержание |
|---|---|---|
| 1 | Сценарий и архитектура | OrderDesk, границы сервисов, диаграмма потоков |
| 2 | Проектирование контракта API | Ресурсы, HTTP-коды, OpenAPI |
| 3 | Модели данных и маппинг | DTO, JSON, версии полей |
| 4 | Сервис каталога на Python | FastAPI, резервы, идемпотентность |
| 5 | Сервис заказов на C# | Minimal API, HttpClient, заказы |
| 6 | Безопасность и устойчивость | JWT, API-ключ, CORS, таймауты |
| 7 | WebSocket и события | Hub, протокол сообщений, heartbeat |
| 8 | Проверка в Postman | Коллекция, E2E, негативные кейсы |
Проверьте себя: Чек-лист самопроверки.
Следующие шаги
- Теория интеграций — 8.05 Микросервисы и интеграция.
- Интеграционное тестирование — 7.05 Проверка взаимодействия компонентов.
- Контейнеризация двух сервисов — 8.06.
См. также
Другие статьи этого же раздела в боковом меню (как на странице "О разделе"). Два сервиса OrderDesk: каталог на Python и заказы на C#, границы ответственности, потоки REST и WebSocket. Ресурсы OrderDesk, таблица методов HTTP, коды ответов и фрагмент OpenAPI для catalog-api и orders-api. Доменные сущности OrderDesk, DTO для REST, маппинг Python (Pydantic) и C# (record + ручной маппер). FastAPI, SQLite, эндпоинты товаров и резервирования, Pydantic и проверка через uvicorn. ASP.NET Core 8, Minimal API, HttpClient к catalog-api, SQLite и создание заказа с резервом. JWT, API-ключ между сервисами, HTTPS, таймауты, идемпотентность и заголовок X-Request-Id в OrderDesk. Протокол JSON-сообщений, hub в ASP.NET Core, heartbeat и подписка клиента на статусы OrderDesk. Коллекция Postman, переменные окружения и сквозной сценарий OrderDesk — товар, заказ, WebSocket. Вопросы для закрепления практикума OrderDesk — catalog-api, orders-api, JWT, API-ключ, WebSocket и Postman.Практикум — сценарий и архитектура OrderDesk
Практикум — проектирование контракта API
Практикум — модели данных и маппинг DTO
Практикум — сервис каталога на Python
Практикум — сервис заказов на C#
Практикум — безопасность и устойчивость
Практикум — WebSocket и события заказов
Практикум — проверка в Postman
Практикум REST и WebSocket — чек-лист самопроверки