Как устроен бэкенд
запрос, обработчик, ответ
Что это
Бэкенд — программа, которая ждёт запросов и отвечает на них. Внутри она устроена всегда одинаково, на любом языке и фреймворке: запрос приходит, маршрутизатор решает, кто его обработает, обработчик делает работу, ответ уходит обратно.
Поняв эту цепочку один раз, ты ориентируешься в любом бэкенд-проекте — меняются слова и синтаксис, схема остаётся.
Как выглядит в коде
Вот эта схема в коде. Рабочий пример на FastAPI:
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
app = FastAPI()
SUBS: dict[int, list[str]] = {7: ["Oslo", "Bergen"]}
class SubOut(BaseModel):
user_id: int
cities: list[str]
@app.get("/subs/{user_id}", response_model=SubOut)
def get_subs(user_id: int) -> SubOut:
if user_id not in SUBS:
raise HTTPException(status_code=404, detail="пользователь не найден")
return SubOut(user_id=user_id, cities=SUBS[user_id])Запрос и ответ, по-настоящему:
curl -i http://127.0.0.1:8765/subs/7HTTP/1.1 200 OK
server: uvicorn
content-length: 40
content-type: application/json
{"user_id":7,"cities":["Oslo","Bergen"]}curl -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8765/subs/999404Как это читать
@app.get("/subs/{user_id}") — маршрут. Декоратор регистрирует функцию:
«вызывай её на GET-запрос по такому адресу» (статья 2.9). Искать вызов
get_subs в проекте бесполезно — её вызывает фреймворк.
user_id: int — часть адреса, превращённая в аргумент. Фреймворк вынет
её из /subs/7 и преобразует в число. Если прислать /subs/abc, обработчик
даже не запустится — придёт ошибка о неверном типе.
response_model=SubOut — форма ответа. Фреймворк проверит, что вернули
именно её, и превратит в JSON.
raise HTTPException(404) — способ ответить ошибкой. Не return, а
raise: исключение перехватывает фреймворк и превращает в HTTP-ответ
(статья 2.8).
Что делает фреймворк, а что ты
Это главное для чтения чужого кода:
| Фреймворк | Ты |
|---|---|
| принимает соединение | решаешь, что делать с данными |
| разбирает URL и находит обработчик | ходишь в базу |
| проверяет типы и схемы | решаешь, что считать ошибкой |
| превращает результат в JSON | |
| ловит исключения и отдаёт коды |
Твоего кода в цепочке — одно звено. Поэтому в бэкенд-проекте файлов много, а читать надо в первую очередь обработчики.
Как сказать ИИ
Покажи все маршруты этого проекта: метод, адрес и функция,
которая его обрабатывает. Таблицей, без кода.Что произойдёт при GET /subs/abc? Обработчик запустится
или ошибка будет раньше?Добавь обработчик GET /subs/{user_id}/count — возвращает
число подписок. 404, если пользователя нет. Остальные
маршруты не трогай.На что смотреть
Логика внутри обработчика. Обработчик должен принять запрос, вызвать нужное и вернуть результат. Если в нём пятьдесят строк с SQL и бизнес-правилами — дальше этот код не переиспользовать и не протестировать.
Обращение к базе прямо в обработчике. То же самое: запросы выносят в отдельный модуль, чтобы их можно было менять, не трогая маршруты.
Ответ без схемы. Без response_model фреймворк отдаст что угодно, включая
поля, которых пользователь видеть не должен.
return вместо raise при ошибке. Вернуть {"error": "не найден"} с
кодом 200 — значит соврать клиенту: формально всё хорошо.
Шпаргалка
Цепочка одинакова везде: клиент → маршрут → обработчик → база → ответ.
Твой код — только обработчик, остальное делает фреймворк.
Маршрут регистрируется декоратором; вызов функции в проекте не найдётся.
Ошибку возвращают через
raise, а неreturn.Незнакомый бэкенд читай со списка маршрутов — это его оглавление.
Логика и запросы к базе выносятся из обработчика.