Перейти до змісту

М4. Web (+ Web Advanced)

Програми говорять мережею: спершу — як клієнт до чужих API, далі — власні сервери на Django і FastAPI.

Уроки модуля:

  • Урок 32. HTTP: requests, httpx, aiohttp — шлях запиту: URL, IP і DNS, порти, TCP-рукостискання, TLS; HTTP як текст (запит сокетом), методи й статус-коди; requests: params, json, заголовки й токен, raise_for_status, тайм-аути й ієрархія винятків, повторні спроби з backoff і чому не для POST, Session; справжній API PyPI; httpx і AsyncClient + gather, aiohttp, потоки; архітектура: свій клієнт до API з доменними винятками, вибір бібліотеки. Практика — на навчальному API диспетчерської smachno_api.py.
  • Урок 33. REST: принципи дизайну API — метео-API викладача (телеграми SYNOP з ogimet.com, pymetdecoder): усі типи API на одних даних — HTTP+CSV, JSON-RPC, GraphQL, SOAP, gRPC, WebSocket, SSE, webhook з підписом HMAC — і як обрати; REST: ресурси й URL, методи й ідемпотентність, статус-коди й формат помилок, фільтри, fields, пагінація, PATCH, 202 Accepted, OpenAPI; кейс v1 → v2; архітектура: репозиторій → FastAPI → клієнт-клас → Streamlit-карта погоди, Docker Compose.
  • Урок 34. Django intro: MVT, ORM, admin — перший крок застосунку нотаток, що виросте до Notes Chat App викладача (кроки 1–2 маршруту Zero to Hero Django-книги): startproject / startapp, settings.py, MVT і шлях запиту, view, path / include, модель Note, makemigrations / sqlmigrate / migrate, ORM (create, filter, lookups, get, лінивий QuerySet, .query, update, delete), шаблон, адмінка й суперкористувач; практика — is_pinned, priority, блокноти.
  • Урок 35. Django: forms, HTML practice — два рефакторинги проєкту уроку 34 на стартовому коді (кроки 2 і 4 Django-книги): голий HTML → Bootstrap CRUD (ModelForm, PRG, messages, base.html, CSRF) і Bootstrap → crispy dashboard (3-рівневі шаблони, FormHelper + Layout, context processor); «Знайди помилку» — is_pinned губиться при створенні.
  • Урок 36. DRF overview + Django vs FastAPI — рефакторинг 3 проєкту уроку 35: REST API поруч зі сторінками поверх тих самих services/selectors (код з Django-книги): REST_FRAMEWORK, вхідний і вихідний серіалізатори, ViewSet + DefaultRouter, @action pin, IsAuthenticated і чому 403, IDOR → 404, PATCH з partial=True, browsable API, OpenAPI (drf-spectacular + extend_schema), тести; той самий API на FastAPI і як обрати; «Знайди помилку» — auto_now не оновлюється з update_fields.
  • Урок 37. Typing + Pydantic — крок 1 новинного агрегатора (FastAPI-гілка): стартовий парсер parse_rbc_news з анотаціями типів (list[RawNews], TypedDict, X | None, Literal), mypy і --strict, модель NewsItem на Pydantic (Field, field_validator, model_validator(mode="before"), frozen), перевірка знімка 168 справжніх новин rbc.ua, validate_news без мовчазних втрат, JSON Schema, TypeAdapter; «Знайди помилку» — URL, розібраний рядком.
  • Урок 38. FastAPI basics + Postman + OpenAPI — крок 2 агрегатора: FastAPI над NewsItem з прототипу news_dashboard — маршрути, Query і Literal, 422, response_model; сховище через Depends і lifespan, підміна залежностей у тестах; POST /api/scrape (aiohttp, gather, знімок, захист від SSRF); /docs і /openapi.json; колекція Postman з перевірками і newman; виміри fastapi_demo: async def + time.sleep — 20 запитів за 40 с, def і await — за 2 с (і як тест навантаження вимірював сам себе). Довідник: FastAPI — архітектура і async.
  • Урок 39. FastAPI + SQLAlchemy: повний CRUD — крок 3 агрегатора: NewsStore → PostgreSQL/SQLite на шарі бази стартового production_bot — async-engine і сесія на запит (get_db), NewsRow (Mapped), NewsRepository з тим самим інтерфейсом, SQL, який генерує SQLAlchemy, INSERT … ON CONFLICT DO NOTHING покроково (і чому id «перескакують»); повний CRUD 201/404/409/204, пошук; Alembic-міграції; з FastAPI 0.118 COMMIT у yield-залежності йде після відповіді → scope="function"; «Знайди помилку» — гонка «перевір, потім встав».
  • Урок 40. Middlewares і кешування (Redis на практиці) — крок 4 агрегатора: HTTP-middleware (X-Request-ID, X-Process-Time, порядок шарів покроково); кеш GET /api/news і /stats у Redis (cache-aside, версія кешу, інвалідація після COMMIT); rate limit зі стартового ai_bot — 429 і Retry-After, атомарні INCR + EXPIRE NX замість «ключ без TTL блокує назавжди», межа фіксованого вікна виміряна; фоновий збір 202 + статус у Redis з polling; «Знайди помилку» — сесія запиту у фоновій задачі: «збережено 168», а в базі 0.
  • Урок 41. Автентифікація та security basics (JWT, hashing, OWASP) — рефакторинг 4 застосунку нотаток на стартовому коді автентифікації: нотатки групи (Q(user) | Q(group__in=…), читати — учасникам, змінювати — автору), перевірка автора в API → 403; паролі — PBKDF2 з сіллю, скидання листом без розкриття акаунтів; JWT на simplejwt (header.payload.signature покроково, підправлений / чужий / прострочений токен → 401, refresh з ротацією, порядок автентифікаторів DRF: 401 чи 403), throttle /api/token/; check --deploy; OWASP Top 10 на нашому коді; «Знайди помилку» — SECRET_KEY у публічному репозиторії.
  • Урок 42. Тестування API (pytest + httpx) — рефакторинг 5 агрегатора новин: переробляємо лише тести уроку 40. Шари unit / integration з маркерами; збережені сторінки rbc.ua як фікстури й тест конвеєра «парсер → модель»; мок мережі й «patch where used» (покрокова діаграма); фейковий HTTP-сервер (aiohttp TestServer) і межа фейку (fakeredis не показує гонок); httpx.AsyncClient + ASGITransport для одночасних запитів; покриття гілок з concurrency = greenlet; прогін на мінімальних версіях залежностей. Тести ловлять 4 помилки: ISO-час, битий байт UTF-8, fakerbc.ua, beautifulsoup4 4.12. «Знайди помилку» — два зелені тести, які разом пропустили помилку контракту.
  • Урок 43. AI-інструменти розробника + ризики й валідація — рефакторинг 6 агрегатора новин і рецензія AI-проєкту. news_hub отримує CLAUDE.md (замість застарілого прикладу з довідника), .claude/settings.json (allow / ask / deny), hook pytest -m unit після кожної правки і skill /add-news-source. Експеримент: Claude Code двічі додає RSS «Української правди» — з голим запитом (101 зелений власний тест, але час у GMT, тиха відмова на битому XML і вигадана фікстура) і за специфікацією з тестів (2 файли, тести не змінено); рецензія знаходить ще 3 випадки поза специфікацією. allow з репозиторію не діє без довіри до папки. Кейс depression_dashboard (Flask + Streamlit + scikit-learn, згенерований AI): 17 тестів рецензії доводять 10 вад, зокрема алфавітний порядок «топ-ознак» через jsonify, вигадані назви кластерів, підробні похідні ознаки в /api/predict, витік даних, незахищений /api/train. Довідник Claude Code — звірений з документацією.
  • Урок 44. Інтеграція LLM API (Gemini / Anthropic) — рефакторинг 7 агрегатора новин: тема, тональність, підсумок і ключові слова від LLM замість правил nlp.py (у знімку всі 168 новин — категорія «Новини»). стартовий ai_service.py → llm.py: один інтерфейс LLMClient для Gemini (асинхронний client.aio, пул моделей: 404/429/5xx — наступна, 400/401/403 — стоп) і Anthropic, FakeLLM для тестів; відповідь — JSON за схемою й перевірка Pydantic з одним повтором; промпт-ін'єкція (дані в <news>, схема з переліками); circuit breaker на INCR + EXPIRE NX → 503 + Retry-After (справжній запуск з невалідним ключем); база → кеш за хешем тексту → модель, токени й вартість, пакетний аналіз у фоні. «Знайди помилку» — схема з extra="forbid", яку Gemini відхиляє 400, хоча всі тести з фейком зелені; контрактний тест без ключа.
  • Урок 45. Архітектура застосунків і патерни — рефакторинг 5 застосунку нотаток (крок 3 Django-книги) і каталог патернів обох проєктів. Правило «хто що бачить» жило у views і selectors кількома копіями, які розійшлися: список, поділений з двома, падав з 500 (MultipleObjectsReturned через M2M + OR), список групи був у переліку, але відкривався з 404. Тепер selectors.*_visible_to / *_owned_by повертають QuerySet — одне правило для сторінок, CBV і API; тест на ast стежить, щоб у views.py і api.py не було ORM. Нотатки, записники й теги — class-based views зі стартового notes_project_cbv (LoginRequiredMixin → OwnerRequiredMixin по MRO, чому нічого з базою в setup()); відкритий редирект ?next= закрито. PostgreSQL через DATABASE_URL (SQLite без змінної), 49 тестів на обох базах, кількість SQL-запитів як контракт (без select_related — 97 замість 8). Каталог: Service layer, CQRS-light, Repository, DI, Strategy (LLMClient), Decorator (GuardedLLM), Factory (make_llm), Template method, Unit of Work — на коді нотаток і news_hub; коли патерн зайвий; «куди класти код».
  • Урок 46. WebSockets + практика: чат — рефакторинг 6 застосунку нотаток (крок 7B Django-книги): груповий чат зі стартового коду — Django Channels, ASGI (ProtocolTypeRouter, daphne), consumer, channel layer (у пам'яті або Redis за REDIS_URL), JS-клієнт. Consumer — ще один транспорт над тими самими selectors і services: членство — selectors.is_group_member, запис — services.post_chat_message (межі тексту й права — на кожне повідомлення). Вилучили з групи або групу видалили → подія після COMMIT закриває відкрите з'єднання кодом 4403; AllowedHostsOriginValidator — захист від Cross-Site WebSocket Hijacking; JS не перепідключається після відмови. Тести — WebsocketCommunicator + TransactionTestCase, 76 на SQLite + InMemory і PostgreSQL + Redis; ноутбук — чат з кількома «браузерами» без сервера.
  • Урок 47. Security advanced — рефакторинг 8 агрегатора news_hub: у проєкті уроку 44 будь-хто міг стерти базу (DELETE /api/news) і запустити платний аналіз. Адмін-JWT зі стартового production_bot: пароль — bcrypt-хеш у env (без passlib, який не працює з bcrypt 5), без секретів «change-me» (не налаштовано → 503, короткий секрет → не стартує), HS256 і обов'язкові exp/sub/role, ліміт спроб входу; тест обходить усі маршрути й порівнює незахищені з переліком PUBLIC. SSRF: RSS-джерела адміна завантажує safe_fetch — IP перевіряє resolver з'єднання (після DNS), кожне перенаправлення знову, порти, розмір, тип; старий захист allowlist-ом обходиться одним 302. Підписані webhook: HMAC(час + сирі байти тіла), вікно 5 хв, SET NX проти повтору, compare_digest, секрет не в URL. 279 тестів на SQLite і PostgreSQL + Redis; ноутбук — підробка токенів, SSRF на локальних серверах, повтор webhook.
  • Урок 48. Telegram Bot API — рефакторинг 9 агрегатора news_hub: Telegram-бот на aiogram 3 зі стартових ai_bot і echo_bot — /news, /digest (аналіз LLM), /subscribe <слово> і сповіщення про нові новини після кожного збору, адмінська /scrape за user_id. Бот — ще один вхід у той самий застосунок: ті самі репозиторії, analyze_news, rate limit на Redis; сесія бази на кожен update (inner middleware), роутер — новий на кожен диспетчер. Відповіді в HTML: усе ззовні екранується (ім'я «Tom & Jerry» у стартовому коді — бот мовчить), довгий текст ділиться між рядками, а не кожні 4000 символів. Сповіщення: лише нові новини (RETURNING), 403 → підписки видаляються, 429 → retry_after. Webhook у FastAPI з секретом у заголовку (verify_secret_token уроку 47), polling — python -m news_hub.bot. Тести й ноутбук — на двійнику Telegram Bot API, без токена й мережі.

Решта уроків — 🚧 у розробці.

Django-книга викладача. Уроки М4 про Django ведуть по маршруту Zero to Hero Django-книги: урок 34 — кроки 1–2, 34 — кроки 2 і 4, 35 — API до нотаток, 38 і 44 — крок 3, 40 — крок 5, 41 — крок 6, 45 — крок 7, 48–49 — кроки 8–9. Стартовий код — готові проєкти, кожен урок — рефакторинг проєкту попереднього (що змінилося, діфи, архітектура до/після); сторінки курсу — стислий урок із практикою, книга — поглиблення (посилання «Поглиблено» в кожному розділі).

17 уроків (лекції #31–47 у навігаційній таблиці v5.0): HTTP/REST → Django intro → DRF/FastAPI → повний CRUD → middlewares/кешування → auth/security basics → тестування API (лекції #31–41, «Web»), потім AI-інструменти розробника, інтеграція LLM API, архітектура застосунків, WebSockets, security advanced, Telegram Bot API (лекції #42–47, «Web Advanced»).

«Web Advanced» — це продовження М4, не окремий модуль: обидва блоки йдуть під одним наскрізним номером уроку, а модулі М5/М6 зберігають свої номери одразу після «Web Advanced» без зсуву.