Бэкенд и HTTP: кто что делает, методы и коды состояния

Цели урока
  • Объяснить, в чём роль бэкенда и чем он отличается от фронтенда
  • Описать поток Client → Server → Database → Server → Client
  • Определить API и Endpoint и распознавать их в настоящих адресах
  • Читать запрос и ответ API и понимать, почему API возвращает JSON
  • Объяснить, что делает каждый из GET, POST, PUT и DELETE, и сопоставить их с CRUD
  • Различать «безопасный» метод (не меняет данные) и метод, который меняет
  • Выбирать правильный код состояния для каждого результата запроса
  • Читать HTTP-запрос и ответ и распознавать метод и код ответа

В этом уроке

Урок состоит из двух глав — в том же порядке, что и в презентации:

  1. Глава 1 — что такое бэкенд: клиент, сервер, база данных, API и Endpoint
  2. Глава 2 — методы HTTP и коды состояния

Глава 1: Что такое бэкенд — клиент, сервер, база данных, API и Endpoint

Что мы изучим?

Теперь мы переходим от программ, которые работают на нашем собственном компьютере, к программам, с которыми другие общаются по сети. Этот урок даёт общую картину и словарь:

  • Бэкенд (Backend) и фронтенд (Frontend).
  • Клиент, сервер и база данных: как они работают вместе.
  • API и Endpoint.

Зачем это нужно?

Каждое знакомое вам приложение (Wolt, Instagram, сайт банка) состоит из двух частей: того, что вы видите (фронтенд), и того, что происходит «за кулисами» (бэкенд): сохранение данных, проверка прав, расчёт цен. Full Stack-разработчики пишут и то, и другое. Разработчики данных каждый день работают с API и базами данных.

К концу этих тем вы построите настоящий бэкенд: сервер, который получает запросы из интернета, сохраняет в базу данных и возвращает ответы.

Объяснение с основ

Фронтенд и бэкенд

ФронтендБэкенд
Что этоЧасть, которую видит пользователь и с которой он работаетЧасть, которая работает на сервере, за кулисами
Где работаетВ браузере / в приложении на телефонеНа серверном компьютере (в облаке / в компании)
РольОтображение, формы, кнопкиБизнес-логика, сохранение данных, безопасность
Пример в магазинеСтраница товара, кнопка «в корзину»Проверка склада, расчёт цены, сохранение заказа
ТехнологииHTML, CSS, JavaScript, ReactPython + FastAPI, Node.js, Java…
Аналогия: ресторан

Фронтенд = зал ресторана: меню, столы, официант, который принимает заказ. Бэкенд = кухня: там действительно готовят еду, проверяют наличие продуктов и соблюдают правила (на кошерной кухне — без мяса с молочным). База данных = кладовая и холодильник: там хранятся все запасы. Посетитель никогда не заходит на кухню или в кладовую. Он общается только с официантом.

Клиент, сервер, база данных — три участника

Помните тему о компьютере, операционной системе и сети? Клиент начинает, сервер отвечает. Теперь добавим третьего участника:

  ┌──────────┐   HTTP Request    ┌──────────┐     SQL query     ┌──────────┐
  │  Client  │ ────────────────► │  Server  │ ─────────────────► │ Database │
  │ (browser,│                   │ (FastAPI │                    │ (MySQL)  │
  │  app)    │ ◄──────────────── │  backend)│ ◄───────────────── │          │
  └──────────┘   HTTP Response   └──────────┘     rows           └──────────┘
  1. Клиент отправляет запрос (Request): «дай мне список студентов».
  2. Сервер (наш бэкенд) получает его, понимает, что просят, и проверяет права и правила.
  3. Сервер спрашивает базу данных: «SELECT всех студентов». (Это ещё один клиент-сервер: по отношению к базе данных наш сервер — клиент! Мы видели это в практике по сетям.)
  4. База данных возвращает строки.
  5. Сервер обрабатывает их и возвращает клиенту ответ (Response), обычно в виде JSON (вспомните урок о JSON!).

Почему клиент не общается с базой данных напрямую? Потому что тогда любой пользователь мог бы читать и удалять всё. Сервер — охранник: он решает, что разрешено, проверяет допустимость и обеспечивает соблюдение правил. Точно как инкапсуляция в теме ООП, только на уровне всей системы.

API — Application Programming Interface

API = интерфейс, который программа открывает, чтобы другие программы могли ею пользоваться. Интерфейс = определённый набор действий: что можно попросить, как просить и что вы получите в ответ.

Идея вам уже знакома! В ООП публичный интерфейс класса (публичные методы) — это ровно «API объекта». Web API — та же идея по сети: вместо shop.place_order(...) вы отправляете HTTP-запрос.

ООП (тема ООП)Web API (сейчас)
shop.get_product("P1")GET /products/P1
shop.add_customer("Dana", ...)POST /customers с телом (Body)
ProductNotFoundErrorКод состояния 404
Публичные методыEndpoint-ы

Endpoint

Endpoint = один адрес в API + одно действие. Сочетание метода (GET/POST…) и пути (Path, /students).

GET     /students        → list all students
GET     /students/7      → get student 7
POST    /students        → create a new student
PUT     /students/7      → update student 7
DELETE  /students/7      → delete student 7

Это пять разных Endpoint-ов, хотя у некоторых из них один и тот же путь. Метод — часть «адреса».

Ресурс (Resource) = «вещь», которой управляет API: students, products, orders. Принятое соглашение: путь — во множественном числе, а идентификатор — после косой черты.

Что делает бэкенд при каждом запросе?

ШагПример
Приём — разобрать метод, путь, телоPOST /students с {"name": "Dana", ...}
Проверка — допустимы ли данные?Возраст — число, в email есть @
Логика — бизнес-правилаТакого email ещё нет
Доступ к данным — база данныхINSERT INTO students ...
Ответ — код состояния + JSON201 Created + новый студент

Как выглядит ответ API

Когда клиент обращается к API, он отправляет запрос, а сервер возвращает ответ. Вот как выглядят оба — например, запрос к API GitHub о пользователе с именем octocat:

GET /users/octocat              <- the request
Host: api.github.com

HTTP/1.1 200 OK                 <- the response
Content-Type: application/json

{"login": "octocat", "name": "The Octocat", "public_repos": 8}
ЧастьЧто она говорит
GET /users/octocatМетод и путь — что запрашивают
200 OKКод ответа — запрос выполнен успешно
Content-Type: application/jsonТело в формате JSON
{"login": ...}Сами данные — не дизайн, не страница, только данные

API возвращает данные, а не отображение: каждый клиент — сайт, приложение на телефоне или другая программа — получает одни и те же данные и показывает их по-своему.

Аналогия: ресторан

Посетитель (клиент) не заходит на кухню. Он заказывает через официанта по меню — это API, а каждое блюдо в меню — Endpoint. Кухня (сервер) готовит блюдо из того, что есть в кладовой (база данных), а официант его приносит.

Дальше мы научимся сами строить такой API с помощью FastAPI.

Типичная ошибка

Ошибка 1: «Данные сохранит фронтенд, зачем нужен бэкенд?» Данные в браузере остаются у одного пользователя, на одном компьютере, и любой может их изменить. Цена, сохранённая в браузере? Пользователь может поменять её на 1 шекель. Всё, что должно быть надёжным, общим и защищённым, живёт в бэкенде.

Ошибка 2: путать API с базой данных. API — это дверь. База данных — кладовая за ней. Клиент никогда не получает прямого доступа к кладовой и всегда идёт через дверь, с её правилами.

Ошибка 3: пути, которые описывают действия, а не ресурсы.

GET  /getAllStudents
POST /createNewStudent
GET  /deleteStudent?id=7

Соглашение (оно называется REST): путь — существительное (ресурс), а метод — глагол. DELETE /students/7, а не GET /deleteStudent. В частности: GET никогда не меняет данные. Браузеры и поисковые роботы отправляют GET автоматически, и удаление через GET — рецепт катастрофы. (Подробнее — во второй главе.)

Итоги

  • Фронтенд = то, что видит пользователь. Бэкенд = логика, данные и безопасность на сервере.
  • Поток: Client → Server → Database → Server → Client. Сервер — охранник: клиент не обращается к базе данных напрямую.
  • API = интерфейс, который программа открывает другим программам. В вебе — через HTTP и JSON.
  • Endpoint = метод + путь. GET /students/7 и DELETE /students/7 — два разных Endpoint-а.
  • Соглашение: путь = ресурс (существительное, во множественном числе). Метод = действие. GET не меняет данные.

Официальная документация

Глава 2: Методы HTTP и коды состояния

Что мы изучим?

  • Четыре главных метода HTTP: GET, POST, PUT, DELETE.
  • Как они сопоставляются с CRUD: Create, Read, Update, Delete.
  • Базовые коды состояния (Status Codes): какой код когда возвращать.
  • Как выглядят запрос и ответ для каждого действия.

Зачем это нужно?

В теме API студентов вы будете писать сервер, и для каждого Endpoint-а нужно будет решить: какой метод? Какой код вернуть при успехе и какой при каждом виде сбоя? Клиент, который общается с вашим сервером (приложение, фронтенд, другой сервис), решает, что делать, по коду: показать данные, показать «не найдено» или попросить пользователя исправить форму. Неправильный код = клиент, который ведёт себя неправильно.

Объяснение с основ

CRUD — четыре действия с данными

Почти каждая система делает со своими данными четыре вещи:

CRUDЗначениеМетод HTTPSQL (тема баз данных)
CreateСозданиеPOSTINSERT
ReadЧтениеGETSELECT
UpdateОбновлениеPUTUPDATE
DeleteУдалениеDELETEDELETE

Эта таблица — вся часть про бэкенд. Каждая строка станет Endpoint-ом и функцией, которая выполняет SQL.

Четыре метода

GET — чтение.

  • «Дай мне»: GET /students, GET /students/7.
  • Без тела (Body). Вся информация — в пути и в параметрах запроса (Query, в следующем уроке).
  • Ничего не меняет на сервере. Это называется безопасным (Safe). Можно отправить его 100 раз, и ничего не изменится.

POST — создание.

  • «Создай что-то новое»: POST /students с телом, которое это описывает.
  • Каждая отправка создаёт ещё один элемент. Две отправки = два студента.
  • Обычно сервер сам задаёт идентификатор (id) и возвращает новый элемент.

PUT — обновление (замена).

  • «Обнови этот элемент»: PUT /students/7 с телом со всеми новыми данными.
  • Повторная отправка того же запроса = тот же результат (студент остаётся с теми же значениями). Это называется идемпотентностью (Idempotent).

DELETE — удаление.

  • «Удали этот элемент»: DELETE /students/7.
  • Обычно без тела.

(Есть и другие методы, например PATCH для частичного обновления отдельных полей, но нам достаточно этих четырёх.)

Аналогия: библиотека

GET = «можно посмотреть книгу?» (смотрите, не забираете). POST = «я дарю библиотеке новую книгу» (добавляется экземпляр). PUT = «замените порванную обложку книги 7 на новую» (та же книга, обновлённая). DELETE = «уберите книгу 7 с полок».

Коды состояния — что отвечает сервер

Напоминание из темы о компьютере, операционной системе и сети: 2xx — успех, 4xx — ошибка клиента, 5xx — ошибка сервера. Вот коды, которые мы будем использовать:

КодНазваниеКогда возвращатьПример на нашем сервере
200OKУспех, и есть ответGET выполнен, PUT выполнен
201CreatedСоздан новый ресурсPOST выполнен
204No ContentУспех, без телаDELETE выполнен
400Bad RequestЗапрос недопустим с точки зрения правилВозраст 7 (нужно 16+), пустое имя
404Not FoundРесурс не существуетGET /students/999
409ConflictКонфликт с существующим состояниемEmail, который уже зарегистрирован
422Unprocessable ContentНеправильная структура данныхОтсутствует поле, текст вместо числа (FastAPI возвращает его автоматически)
500Internal Server ErrorБаг на сервереИсключение, которое не поймали в нашем коде

Принцип принятия решения:

Did it work?
├── yes → created something new?  → 201
│         nothing to return?      → 204
│         otherwise               → 200
└── no  → the client's fault?
          ├── resource doesn't exist        → 404
          ├── wrong structure / types       → 422
          ├── breaks a business rule        → 400
          ├── conflicts with existing data  → 409
          └── our code crashed              → 500  (fix the bug!)

4xx и 5xx — почему это важно?

  • 4xx = «вам (клиенту) нужно что-то изменить»: исправить форму или запросить то, что существует. Повторная попытка без изменений снова не удастся.
  • 5xx = «я (сервер) дал сбой». Клиент ничего плохого не сделал. Нужно исправлять код сервера.

Сервер, который возвращает 500 на плохой ввод пользователя, содержит баг: он должен был проверить ввод и вернуть 4xx. (Помните сервер-калькулятор из темы о компьютере, операционной системе и сети, который падал на «hello»?)

Запросы и ответы — примеры

Вот как выглядят запросы для каждого из действий и код, который возвращает сервер:

POST   /students     {"name": "Dana"}   -> 201 Created
GET    /students/7                      -> 200 OK
PUT    /students/7   {"name": "Dana C"} -> 200 OK
DELETE /students/7                      -> 204 No Content
GET    /students/99                     -> 404 Not Found

Когда отправлять тело

МетодТело?Что в нём
GETНетВы только читаете — отправлять нечего
POSTДаДанные нового ресурса в JSON
PUTДаВсе обновлённые данные
DELETEНетДостаточно идентификатора в пути

Дальше, в FastAPI, мы увидим, как наш сервер принимает каждый из этих запросов и возвращает правильный код.

Типичная ошибка

Ошибка 1: GET, который меняет данные.

GET /students/7/delete

Браузеры заранее загружают ссылки, а поисковые системы обходят каждую ссылку (Crawling). Такая ссылка удалит студентов без чьего-либо намерения. Изменение данных — только POST, PUT и DELETE.

Ошибка 2: возвращать 200 на всё, с «error» внутри JSON.

{"status": "error", "message": "student not found"}

…с кодом 200. Клиент (а также браузеры и системы мониторинга) видят 200 и «думают», что всё прошло успешно. Код — часть ответа. Несуществующий студент = 404.

Ошибка 3: 500 на плохой ввод. Сервер, который выполняет int(age) без проверки и падает на "abc" → 500. Это не ошибка клиента, и его не нужно наказывать. Это баг на сервере. Проверяйте ввод и возвращайте 4xx с объяснением.

Ошибка 4: 404 или 400. GET /students/999 (допустимо, но не существует) → 404. POST /students с возрастом -5 (существует, но недопустимо) → 400. Вопрос: «ресурс не существует или запрос недопустим?»

Итоги

  • CRUD ↔ HTTP: Create = POST, Read = GET, Update = PUT, Delete = DELETE.
  • GET безопасен: не меняет данные и не имеет тела. POST/PUT отправляют тело в JSON с Content-Type: application/json.
  • Успех: 200 (есть ответ), 201 (создано), 204 (без содержимого).
  • Ошибка клиента: 404 (не существует), 400 (нарушает правило), 409 (конфликт), 422 (неправильная структура или тип).
  • 500 = баг на сервере. Плохой ввод должен получать 4xx, а не вызывать падение.
  • Код — часть ответа. Не возвращайте 200 с «error» внутри.

Официальная документация

Практика

Вопросы на понимание материала урока — без кода.

Упражнение 1: Кто что делает?

Для каждого действия — где оно происходит: в клиенте, на сервере или в базе данных?

  1. Пользователь нажимает кнопку «Зарегистрироваться».
  2. Проверка, что email ещё не зарегистрирован.
  3. Долговременное сохранение нового студента.
  4. Показ сообщения «Вы успешно зарегистрировались».
  5. Решение, какой код состояния вернуть.
Показать решение
  1. Клиент — интерфейс, который видит пользователь.
  2. Сервер — логика и правила (с помощью запроса к базе данных).
  3. База данных — постоянное хранилище.
  4. Клиент — показывает то, что вернул сервер.
  5. Сервер — именно он решает, что произошло, и возвращает ответ.
Client  --HTTP request-->  Server  --SQL query-->  Database
Client  <--HTTP response-- Server  <---rows------  Database

Упражнение 2: Endpoint-ы

Напишите пять Endpoint-ов API для управления товарами (/products): список, один товар, создание, обновление и удаление. Для каждого — метод, путь и что он делает.

Показать решение
GET     /products      -> list all products
GET     /products/7    -> get product 7
POST    /products      -> create a new product
PUT     /products/7    -> update product 7
DELETE  /products/7    -> delete product 7

Endpoint = метод + путь. Один и тот же путь (/products/7) делает три разные вещи в зависимости от метода.

Упражнение 3: Читаем ответ API

Сервер вернул следующий ответ:

HTTP/1.1 200 OK
Content-Type: application/json

{"login": "octocat", "name": "The Octocat", "public_repos": 8, "blog": null}
  1. Успешен ли запрос? Как вы это узнали?
  2. В каком формате данные и как вы это узнали?
  3. Как зовут пользователя и сколько у него репозиториев?
  4. Что означает null?
Показать решение
  1. Да — код 200 OK.
  2. JSON — так говорит заголовок (Header) Content-Type: application/json, и так выглядит тело.
  3. Имя — The Octocat, и у него 8 репозиториев.
  4. null в JSON означает «нет значения» — у пользователя нет сайта (blog). (В Python, когда мы прочитаем это позже, он станет None.)

Упражнение 4: CRUD ↔ методы

Сопоставьте каждое действие CRUD с методом HTTP и подходящим кодом ответа при успехе.

Create    Read    Update    Delete
Показать решение
CRUDМетодКод при успехе
CreatePOST201 Created
ReadGET200 OK
UpdatePUT200 OK
DeleteDELETE204 No Content

Упражнение 5: Какой код вернуть?

Для каждого случая — какой код состояния должен вернуть сервер?

  1. Создан новый студент.
  2. Запрошен студент 99, а его нет.
  3. Кто-то попытался создать студента с email, который уже зарегистрирован.
  4. Студент удалён — и возвращать нечего.
  5. Отправлен возраст 7, а минимальный возраст — 16.
  6. Сервер упал из-за бага в коде.
Показать решение
  1. 201 — создано что-то новое.
  2. 404 — ресурс не существует.
  3. 409 — конфликт с тем, что уже есть.
  4. 204 — успешно, без тела.
  5. 400 — запрос не соответствует правилам (ошибка клиента).
  6. 500 — ошибка сервера.