Модуль 9

Request body та Pydantic-моделі

Ось готовий урок, створений спеціально за твоїм запитом, у стилі енергійних лекцій CS50.


🎓 Урок: Request body та Pydantic-моделі

Привіт, світ! 👋 Мене звати [Твоє Ім'я], і сьогодні ми зануримось у серце сучасної веб-розробки на Python (FastAPI).

Ми вже вміємо передавати прості дані через URL (пам’ятаєте query-параметри? ?id=5&q=search). Але що, якщо нам потрібно передати щось більше? Щось складніше?


1. 🔥 Вступ: Проблема та мотивація

Уявіть, що ви замовляєте піцу онлайн. 🍕

Якщо використовувати лише URL-параметри (те, що йде після знаку питання), ваше посилання виглядало б як жахливий монстр: my-pizza.com/order?type=pepperoni&size=large&crust=thin&extra_cheese=true&address=Kyiv_Khreschatyk_1&comment=do_not_ring_doorbell...

А тепер уявіть, що ви реєструєте користувача. Ви справді хочете передавати пароль прямо в адресному рядку, де його побачить будь-хто, хто стоїть за вашою спиною, або збереже історія браузера? 😱 Звісно, ні! Це небезпечно, незручно і непрофесійно.

Риторичне запитання: Як нам передати "пакет" даних (об'єкт, структуру, цілий документ) так, щоб це було безпечно, зручно і, головне, щоб сервер зрозумів, що ми йому надіслали?

Аналогія з поштою: 📮 * Query params (URL) — це написи на конверті. Їх бачать усі, там мало місця. * Request Body (Тіло запиту) — це лист всередині конверта. Там може бути багато сторінок, фотографії, структурований текст. І це приховано від сторонніх очей (особливо з HTTPS).

Але тут виникає проблема. Якщо хтось надішле вам у конверті не лист, а, скажімо, цеглу? Або лист китайською мовою, яку ви не знаєте? Ваш сервер (як і ви) просто "зламається".

Ось тут на сцену виходить Pydantic. Це ваш особистий охоронець-перекладач, який перевіряє вміст конверта ще до того, як він потрапить до вас на стіл.


2. 🧠 Теоретична база (без нудних лекцій)

Давайте розберемося, що відбувається "під капотом".

Що таке Request Body?

Це дані, які кліент (браузер, мобільний додаток) відправляє API. Зазвичай у форматі JSON (JavaScript Object Notation). Це стандарт де-факто. Він виглядає як словник у Python: {"name": "Ivan", "age": 25}.

Що таке Pydantic?

Це бібліотека Python, яка робить одну річ геніально: Data Validation (валідацію даних).

Коли FastAPI отримує запит: 1. Він бере JSON. 2. Передає його Pydantic-моделі (яку ми створимо). 3. Pydantic каже: "Ага, тут має бути число, а тут рядок". 4. Якщо все ок — він перетворює JSON у зручний Python-об'єкт. 5. Якщо ні — він автоматично "відшиває" клієнта з чіткою помилкою.

📌 Що треба запам'ятати залізно:

  • Ми створюємо класи, які наслідуються від BaseModel.
  • Ми використовуємо Type Hints (підказки типів: str, int, bool), щоб задати правила.

3. 🧪 Приклади: Від "Hello" до Pro

Приклад 1: Мінімальний (Рівень "Новачок")

Створимо модель товару. Нам потрібна назва і ціна.

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

# 1. Описуємо "форму" наших даних
class Item(BaseModel):
    name: str
    price: float

# 2. Використовуємо це в ендпоінті
@app.post("/items/")
async def create_item(item: Item):
    # Тут item — це вже не просто JSON, це об'єкт Python!
    return {"message": f"Товар {item.name} створено з ціною {item.price}"}

👀 Запитання до вас: Що станеться, якщо я надішлю такий JSON: {"name": "Laptop", "price": "дорого"}? . . . Відповідь: Pydantic викине помилку! Тому що "дорого" — це str, а ми вимагали float. Він захищає ваш код від падіння.


Приклад 2: Реальний світ (Рівень "Junior")

У реальності деякі поля обов'язкові, а деякі — ні. Давайте додамо опис товару, якого може і не бути, та податок.

from typing import Optional

class Product(BaseModel):
    name: str
    description: str | None = None  # Опціональне поле (Python 3.10+)
    price: float
    tax: float = 10.5               # Значення за замовчуванням

@app.post("/products/")
async def create_product(product: Product):
    total_price = product.price + product.tax
    return {
        "product": product.name, 
        "final_price": total_price,
        "desc": product.description
    }

Тут магія Pydantic в дії: * Якщо клієнт не надішле tax, Pydantic сам підставить 10.5. * Якщо не надішле description, там буде None. * Але якщо не надішле price — буде помилка, бо це поле обов'язкове!


4. 🛠 Практична частина

Прийшов час бруднити руки кодом! Відкривайте редактор.

Завдання 1: Реєстрація Створіть модель User, яка має: * username (рядок) * email (рядок) * age (ціле число) Напишіть ендпоінт POST /users/, який приймає цю модель і повертає повідомлення: "Користувач [username] зареєстрований".

Завдання 2: "А ти повнолітній?" Додайте логіку в ендпоінт із Завдання 1. Якщо age менше 18, повертайте JSON {"error": "Вам сюди не можна"}. (Підказка: використовуйте звичайний if всередині функції).

Завдання 3: Робота над помилками Запустіть код. Спробуйте надіслати в age дробове число (наприклад, 25.5). Що зробив Pydantic? (Він спробував округлити чи видав помилку? Перевірте!).

Завдання 4: Міні-кейс "Блог" Створіть модель BlogPost: * title * content * published (булеве значення, за замовчуванням True). Зробіть так, щоб при створенні поста ви повертали кількість слів у content.

Челлендж "А що, якщо..." Що, якщо в моделі ми хочемо передати список тегів (наприклад, ["news", "tech"])? Спробуйте здогадатися, як це описати в Pydantic, використовуючи list або list[str].


5. 💡 Мислення як у розробника

Як думає досвідчений інженер, коли працює з моделями?

  1. "Не довіряй нікому". Новачок думає: "Я ж роблю фронтенд, я точно надішлю правильні дані". Профі знає: "Фронтенд можна обійти через Postman або curl. Валідація на бекенді (Pydantic) — це єдиний захист".

  2. Розділяй та володарюй. Не пишіть валідацію вручну (if "name" in data...). Це "спагетті-код". Винесіть це в Pydantic-модель. Ваш код функції має займатися бізнес-логікою (збереженням у БД, обробкою), а не перевіркою типів.

  3. Автодоповнення — це суперсила. 🦸‍♂️ Оскільки ви описали типи в класі class Item(BaseModel), ваша IDE (VS Code, PyCharm) буде підказувати вам поля через крапку: item.nam... -> item.name. Це економить години пошуку одруківок!


6. 🧩 Підсумок

Сьогодні ми зробили величезний крок вперед.

  • Ми відмовилися від хаосу в URL.
  • Ми навчилися передавати складні об'єкти через Request Body.
  • Ми найняли Pydantic працювати нашим "фейс-контролем".

Що ви тепер вмієте? Ви можете створити API, яке приймає дані реєстрації, замовлення товарів, створення постів — будь-що, що вимагає введення даних користувачем. І ви робите це безпечно!

🔜 Тизер наступного уроку: Зараз ми просто повертаємо дані назад користувачу. Але це трохи безглуздо, правда? У наступному уроці ми дізнаємося, як зберегти ці дані назавжди, підключивши справжню базу даних!

А поки — код сам себе не напише. Успіхів! 💻🚀