# Бэкенд и HTTP: кто что делает, методы и коды состояния<no value>

## В этом уроке

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

```text
  ┌──────────┐   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`).

```text
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 ...` |
| **Ответ** — код состояния + JSON | `201 Created` + новый студент |

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

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

```text
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 возвращает **данные**, а не отображение: каждый клиент — сайт, приложение на телефоне или другая программа — получает одни и те же данные и показывает их по-своему.

{{< box "analogy" "Аналогия: ресторан" >}}
Посетитель (**клиент**) не заходит на кухню. Он заказывает через официанта по меню — это **API**, а каждое блюдо в меню — **Endpoint**. Кухня (**сервер**) готовит блюдо из того, что есть в кладовой (**база данных**), а официант его приносит.
{{< /box >}}

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

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

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

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

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

```text
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 не меняет данные.

<!-- docs:start — generated by scripts/intro6/site_docs.py; edit the links there -->

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

- [MDN — Introduction to the server side](https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps/Introduction)
- [MDN Glossary — API](https://developer.mozilla.org/en-US/docs/Glossary/API)
- [MDN Glossary — JSON](https://developer.mozilla.org/en-US/docs/Glossary/JSON)

<!-- docs:end -->

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

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

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

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

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

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

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

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

| CRUD | Значение | Метод HTTP | SQL (тема баз данных) |
|---|---|---|---|
| **C**reate | Создание | **POST** | `INSERT` |
| **R**ead | Чтение | **GET** | `SELECT` |
| **U**pdate | Обновление | **PUT** | `UPDATE` |
| **D**elete | Удаление | **DELETE** | `DELETE` |

**Эта таблица — вся часть про бэкенд.** Каждая строка станет 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** для частичного обновления отдельных полей, но нам достаточно этих четырёх.)

{{< box "analogy" "Аналогия: библиотека" >}}
**GET** = «можно посмотреть книгу?» (смотрите, не забираете). **POST** = «я дарю библиотеке новую книгу» (добавляется экземпляр). **PUT** = «замените порванную обложку книги 7 на новую» (та же книга, обновлённая). **DELETE** = «уберите книгу 7 с полок».
{{< /box >}}

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

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

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

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

```text
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»?)

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

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

```text
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, который меняет данные.**

```text
GET /students/7/delete
```

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

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

```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» внутри.

<!-- docs:start — generated by scripts/intro6/site_docs.py; edit the links there -->

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

- [MDN — HTTP request methods](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Methods)
- [MDN — HTTP response status codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status)
- [MDN — HTTP messages](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Messages)

<!-- docs:end -->

<!-- exercises:start — generated by scripts/intro6/sync_site_exercises.py; edit scripts/intro6/exercises/ -->
## Практика

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

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

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

1. Пользователь нажимает кнопку «Зарегистрироваться».
2. Проверка, что email ещё не зарегистрирован.
3. Долговременное сохранение нового студента.
4. Показ сообщения «Вы успешно зарегистрировались».
5. Решение, какой код состояния вернуть.

{{< solution >}}
1. **Клиент** — интерфейс, который видит пользователь.
2. **Сервер** — логика и правила (с помощью запроса к базе данных).
3. **База данных** — постоянное хранилище.
4. **Клиент** — показывает то, что вернул сервер.
5. **Сервер** — именно он решает, что произошло, и возвращает ответ.

```text
Client  --HTTP request-->  Server  --SQL query-->  Database
Client  <--HTTP response-- Server  <---rows------  Database
```
{{< /solution >}}

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

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

{{< solution >}}
```text
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`) делает три разные вещи в зависимости от метода.
{{< /solution >}}

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

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

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

{"login": "octocat", "name": "The Octocat", "public_repos": 8, "blog": null}
```

1. Успешен ли запрос? Как вы это узнали?
2. В каком формате данные и как вы это узнали?
3. Как зовут пользователя и сколько у него репозиториев?
4. Что означает `null`?

{{< solution >}}
1. **Да** — код **200 OK**.
2. **JSON** — так говорит заголовок (Header) `Content-Type: application/json`, и так выглядит тело.
3. Имя — **The Octocat**, и у него **8** репозиториев.
4. `null` в JSON означает **«нет значения»** — у пользователя нет сайта (`blog`). (В Python, когда мы прочитаем это позже, он станет `None`.)
{{< /solution >}}

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

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

```text
Create    Read    Update    Delete
```

{{< solution >}}
| CRUD | Метод | Код при успехе |
|---|---|---|
| Create | `POST` | **201** Created |
| Read | `GET` | **200** OK |
| Update | `PUT` | **200** OK |
| Delete | `DELETE` | **204** No Content |
{{< /solution >}}

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

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

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

{{< solution >}}
1. **201** — создано что-то новое.
2. **404** — ресурс не существует.
3. **409** — конфликт с тем, что уже есть.
4. **204** — успешно, без тела.
5. **400** — запрос не соответствует правилам (ошибка клиента).
6. **500** — ошибка сервера.
{{< /solution >}}

<!-- exercises:end -->
